gnodet-bot commented on code in PR #27582:
URL: https://github.com/apache/camel/pull/27582#discussion_r4221354747


##########
dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ai/CatalogDocs.java:
##########
@@ -457,33 +461,123 @@ private static JsonObject eipDoc(
     private static void putNestedOptions(
             CamelCatalog catalog, EipModel model, String filter, OptionScope 
scope, JsonObject result) {
         JsonArray nested = new JsonArray();
-        String example = null;
+        String[] example = new String[1];
+        JsonObject yamlNodes = null;
         for (BaseOptionModel opt : model.getOptions()) {
             if (!"element".equals(opt.getKind())) {
                 continue;
             }
+            if (isWrittenAsKind(opt)) {
+                // the element is written as one of its kinds, and the options 
are the ones of the kinds: the error
+                // handler's deadLetterUri is errorHandler: 
{deadLetterChannel: {deadLetterUri: ...}} (CAMEL-25377).
+                // An option that several kinds have is listed once, with the 
other kinds in alsoUnder.
+                Map<String, JsonObject> byName = new LinkedHashMap<>();
+                for (String kind : opt.getOneOfs()) {
+                    EipModel element = catalog.eipModel(kind);
+                    if (element == null || element.getOptions() == null) {
+                        continue;
+                    }
+                    JsonArray found = new JsonArray();
+                    addNestedOptions(element, kind, false, filter, scope, 
found, example);
+                    for (Object f : found) {
+                        JsonObject o = (JsonObject) f;
+                        JsonObject first = 
byName.putIfAbsent(o.getString("name"), o);
+                        if (first != null) {
+                            JsonArray also = (JsonArray) 
first.computeIfAbsent("alsoUnder", k -> new JsonArray());
+                            also.add(kind);
+                        }
+                    }
+                }
+                nested.addAll(byName.values());
+                continue;
+            }
             EipModel element = catalog.eipModel(opt.getName());
             // the option must hold that model, not one that only shares its 
name (templatedRoute.bean is a bean
             // factory, not the bean EIP)
             if (element == null || element.getOptions() == null || !holds(opt, 
element)) {
                 continue;
             }
-            boolean list = "array".equals(opt.getType());
-            for (BaseOptionModel inner : element.getOptions()) {
-                if (matchesOptionFilter(inner, filter) && scope.accepts(inner, 
filter)) {
-                    JsonObject o = optionToJson(inner, null);
-                    o.put("under", opt.getName());
-                    nested.add(o);
-                    if (example == null) {
-                        example = opt.getName() + ": " + (list ? "[{" : "{") + 
inner.getName() + ": ..." + (list ? "}]" : "}");
-                    }
-                }
+            if (yamlNodes == null) {
+                yamlNodes = yamlDslNodes(catalog);
             }
+            String key = yamlKey(yamlNodes, model.getName(), opt.getName(), 
element);
+            addNestedOptions(element, key, "array".equals(opt.getType()), 
filter, scope, nested, example);
         }
         if (!nested.isEmpty()) {
             result.put("nestedOptions", nested);
             result.put("nestedHint", "options of an element of " + 
model.getName() + ": write them under that element,"
-                                     + " for example " + example);
+                                     + " for example " + example[0]);
+        }
+    }
+
+    private static void addNestedOptions(
+            EipModel element, String under, boolean list, String filter, 
OptionScope scope, JsonArray nested,
+            String[] example) {
+        for (BaseOptionModel inner : element.getOptions()) {
+            if (matchesOptionFilter(inner, filter) && scope.accepts(inner, 
filter)) {
+                JsonObject o = optionToJson(inner, null);
+                o.put("under", under);
+                nested.add(o);
+                if (example[0] == null) {
+                    example[0] = under + ": " + (list ? "[{" : "{") + 
inner.getName() + ": ..." + (list ? "}]" : "}");
+                }
+            }
+        }
+    }
+
+    /**
+     * Whether the option is a single element written as one of its kinds, not 
under its own name: the error handler is
+     * errorHandler: {deadLetterChannel: {...}}, never errorHandlerType:. Not 
a list such as outputs (written under
+     * steps:), nor an element whose kind is its own name (when).
+     */
+    private static boolean isWrittenAsKind(BaseOptionModel opt) {
+        return "element".equals(opt.getKind()) && 
"object".equals(opt.getType()) && opt.getOneOfs() != null
+                && !opt.getOneOfs().isEmpty() && 
!opt.getOneOfs().contains(opt.getName());
+    }
+
+    /**
+     * The YAML DSL key of an element of an EIP, from the YAML DSL model of 
the catalog: the catalog names an element
+     * after its model, which is not always its YAML key (routeTemplate's 
templateParameter is written as parameters:).
+     * The element is the YAML child of that name, else the one whose model 
has the same title. Falls back to the
+     * catalog name.
+     */
+    static String yamlKey(JsonObject yamlNodes, String eip, String name, 
EipModel element) {
+        JsonObject node = yamlNodes != null ? (JsonObject) yamlNodes.get(eip) 
: null;
+        JsonArray children = node != null ? (JsonArray) node.get("children") : 
null;
+        if (children == null) {
+            return name;
+        }
+        for (Object c : children) {
+            if (name.equals(((JsonObject) c).getString("name"))) {
+                return name;
+            }
+        }
+        for (Object c : children) {
+            JsonObject child = (JsonObject) c;
+            String ref = child.getString("ref");
+            if (ref == null) {
+                continue;
+            }
+            JsonObject refNode = (JsonObject) yamlNodes.get(ref);
+            if (ref.equals(element.getName())
+                    || refNode != null && element.getTitle() != null && 
element.getTitle().equals(refNode.getString("title"))) {

Review Comment:
   💡 **Nit:** `&&` binds tighter than `||` so behaviour is correct, but 
explicit parentheses make the intent immediately clear:
   
   ```suggestion
               if (ref.equals(element.getName())
                       || (refNode != null && element.getTitle() != null && 
element.getTitle().equals(refNode.getString("title")))) {
   ```



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