Croway commented on code in PR #27815:
URL: https://github.com/apache/camel/pull/27815#discussion_r4269320111


##########
dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocs.java:
##########
@@ -1829,7 +1842,43 @@ public static JsonObject optionToJson(BaseOptionModel 
opt, String scope) {
             o.put("oneOf", oneOf);
             o.put("yaml", "write one of oneOf as the key, not '" + 
opt.getName() + "': for example "
                           + opt.getOneOfs().get(0) + ": {...}");
+        } else {
+            String shape = yamlShape(opt);
+            if (shape != null) {
+                o.put("yaml", shape);
+            }
         }
         return o;
     }
+
+    /**
+     * How an option whose type says only object or array is written in YAML 
(CAMEL-25539): an expression has its
+     * language as the key (handled: true fails the schema), and a list of 
properties is a list of key/value pairs
+     * (namespace of xpath). The example comes first and is valid YAML, the 
explanation follows as a comment. Null for
+     * any other option.
+     */
+    static String yamlShape(BaseOptionModel opt) {
+        String name = opt.getName();
+        if ("expression".equals(opt.getKind()) && 
EXPRESSION_SUB_ELEMENT.equals(opt.getJavaType())) {
+            if (opt.isAsPredicate()) {
+                return name + ": {constant: \"true\"}  # a predicate with its 
language as the key, not a plain"

Review Comment:
   Changed to `{constant: {expression: "true"}}` for the predicates and 
`{header: {expression: myKey}}` for the other expression options (d0126776ab29).



##########
dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocs.java:
##########
@@ -1829,7 +1842,43 @@ public static JsonObject optionToJson(BaseOptionModel 
opt, String scope) {
             o.put("oneOf", oneOf);
             o.put("yaml", "write one of oneOf as the key, not '" + 
opt.getName() + "': for example "
                           + opt.getOneOfs().get(0) + ": {...}");
+        } else {
+            String shape = yamlShape(opt);
+            if (shape != null) {
+                o.put("yaml", shape);
+            }
         }
         return o;
     }
+
+    /**
+     * How an option whose type says only object or array is written in YAML 
(CAMEL-25539): an expression has its
+     * language as the key (handled: true fails the schema), and a list of 
properties is a list of key/value pairs
+     * (namespace of xpath). The example comes first and is valid YAML, the 
explanation follows as a comment. Null for
+     * any other option.
+     */
+    static String yamlShape(BaseOptionModel opt) {
+        String name = opt.getName();
+        if ("expression".equals(opt.getKind()) && 
EXPRESSION_SUB_ELEMENT.equals(opt.getJavaType())) {
+            if (opt.isAsPredicate()) {
+                return name + ": {constant: \"true\"}  # a predicate with its 
language as the key, not a plain"
+                       + " true/false; simple: instead of constant: for a 
condition";
+            }
+            return name + ": {header: myKey}  # an expression with its 
language as the key (header, simple, jq, ...)";
+        }
+        if ("element".equals(opt.getKind()) && "object".equals(opt.getType()) 
&& opt.isAsPredicate()
+                && (opt.getOneOfs() == null || opt.getOneOfs().isEmpty())) {
+            return name + ": {simple: \"${header.foo} == 'bar'\"}  # a 
predicate with its language as the key"

Review Comment:
   The onWhen hint is now `onWhen: {expression: {simple: {expression: 
"${header.foo} == 'bar'"}}}`.



##########
dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocsTest.java:
##########
@@ -589,4 +589,98 @@ void yamlKeyFallsBackToTheCatalogName() {
         EipModel element = new 
DefaultCamelCatalog().eipModel("templateParameter");
         assertEquals("templateParameter", CatalogDocs.yamlKey(null, 
"routeTemplate", "templateParameter", element));
     }
+
+    /** CAMEL-25539: onException says it is a top-level entry, and handled 
that it is an expression. */
+    @Test
+    void onExceptionSaysWhereItGoesAndTheShapeOfHandled() {
+        CamelCatalog catalog = new DefaultCamelCatalog();
+        var doc = CatalogDocs.catalogDoc(catalog, "onException", null, "eip", 
null, "all", false, false, null);
+        assertTrue(doc.getString("placement").startsWith("top-level entry"), 
doc.toJson());
+        assertTrue(doc.getString("sampleHint").contains("camel_catalog_sample 
name=onException"), doc.toJson());
+        assertEquals("handled: {constant: \"true\"}", yamlExample(option(doc, 
"handled")));
+        assertEquals("continued: {constant: \"true\"}", 
yamlExample(option(doc, "continued")));
+        assertTrue(yamlExample(option(doc, "onWhen")).startsWith("onWhen: 
{simple: "), doc.toJson());
+        // the elements written in their own way keep no hint
+        assertFalse(option(doc, "redeliveryPolicy").containsKey("yaml"), 
doc.toJson());
+        assertFalse(option(doc, "exception").containsKey("yaml"), 
doc.toJson());
+    }
+
+    /** CAMEL-25539: each kind of EIP says where it goes, and a step has no 
shape hint it does not need. */
+    @Test
+    void placementByKindOfEip() {
+        CamelCatalog catalog = new DefaultCamelCatalog();
+        var doc = CatalogDocs.catalogDoc(catalog, "errorHandler", null, "eip", 
null, null, false, false, null);
+        assertTrue(doc.getString("placement").startsWith("errorHandler: with 
the kind"), doc.toJson());
+        doc = CatalogDocs.catalogDoc(catalog, "routeConfiguration", null, 
"eip", null, null, false, false, null);
+        assertTrue(doc.getString("placement").startsWith("top-level entry"), 
doc.toJson());
+        doc = CatalogDocs.catalogDoc(catalog, "when", null, "eip", null, null, 
false, false, null);
+        assertTrue(doc.getString("placement").startsWith("a part of choice"), 
doc.toJson());
+        doc = CatalogDocs.catalogDoc(catalog, "split", null, "eip", null, 
"all", false, false, null);
+        assertTrue(doc.getString("placement").startsWith("a step inside the 
steps of a route"), doc.toJson());
+        for (Object o : (JsonArray) doc.get("options")) {
+            assertFalse(((JsonObject) o).containsKey("yaml"), ((JsonObject) 
o).toJson());
+        }
+    }
+
+    /** CAMEL-25539: the shape hints show the expected YAML, which passes the 
YAML DSL schema and the catalog checks. */
+    @Test
+    void theShapeHintsAreValidYaml() {
+        CamelCatalog catalog = new DefaultCamelCatalog();
+        var onException = CatalogDocs.catalogDoc(catalog, "onException", null, 
"eip", null, "all", false, false, null);
+        var aggregate = CatalogDocs.catalogDoc(catalog, "aggregate", null, 
"eip", null, "all", false, false, null);
+        var xpath = CatalogDocs.catalogDoc(catalog, "xpath", null, "language", 
null, null, false, false, null);
+        // the namespace of xpath, xquery and xtokenize is a list of key/value 
pairs
+        assertEquals("namespace: [{key: c, value: 
\"http://acme.com/cheese\"}]";, yamlExample(option(xpath, "namespace")));
+        for (String language : List.of("xquery", "xtokenize")) {
+            var doc = CatalogDocs.catalogDoc(catalog, language, null, 
"language", null, "all", false, false, null);
+            assertTrue(yamlExample(option(doc, 
"namespace")).startsWith("namespace: [{key: c, "), doc.toJson());
+        }
+        String yaml = """
+                - onException:
+                    exception: [java.io.IOException]
+                    %s
+                    %s
+                    %s
+                    steps:
+                      - log: failed
+                - onException:
+                    exception: [java.net.ConnectException]
+                    %s
+                - route:
+                    from:
+                      uri: direct:start
+                      steps:
+                        - setHeader:
+                            name: price
+                            expression:
+                              xpath:
+                                expression: /c:order/c:price/text()
+                                %s
+                        - aggregate:
+                            aggregationStrategy: 
"#class:org.apache.camel.processor.aggregate.GroupedBodyAggregationStrategy"
+                            %s
+                            %s
+                            steps:
+                              - log: done
+                """.formatted(
+                yamlExample(option(onException, "handled")), 
yamlExample(option(onException, "onWhen")),
+                yamlExample(option(onException, "retryWhile")), 
yamlExample(option(onException, "continued")),
+                yamlExample(option(xpath, "namespace")), 
yamlExample(option(aggregate, "correlationExpression")),
+                yamlExample(option(aggregate, "completionPredicate")));
+        assertEquals(List.of(), SourceValidator.validateCamelYaml(yaml, 
catalog), yaml);

Review Comment:
   The hint YAML is now also checked with `new YamlValidator(true)`; putting a 
hint back to the shorthand makes the test fail with the "deprecated compact 
notation" error.



##########
dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocs.java:
##########
@@ -1702,6 +1708,13 @@ private static JsonObject eipDoc(EipModel model, String 
filter, OptionScope scop
         result.put("input", model.isInput());
         result.put("output", model.isOutput());
         addCommonModelFields(result, model);
+        // where it goes: onException written as a step inside a route fails 
the schema (CAMEL-25539)
+        String placement = CatalogSamples.placement(model);
+        if (placement != null) {
+            result.put("placement", placement);
+        }
+        result.put("sampleHint", "camel_catalog_sample name=" + model.getName()

Review Comment:
   `sampleHint` is added only when `CatalogSamples.hasEipSample` finds a sample 
through the same lookup `camel_catalog_sample` uses; the test checks 
onException and split have it and pausable does not.



-- 
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]

Reply via email to