diff --git a/zerver/lib/markdown/api_arguments_table_generator.py b/zerver/lib/markdown/api_arguments_table_generator.py
index d8155ee9c2..b43b97cf35 100644
--- a/zerver/lib/markdown/api_arguments_table_generator.py
+++ b/zerver/lib/markdown/api_arguments_table_generator.py
@@ -1,6 +1,6 @@
import json
import re
-from typing import Any, List, Mapping, Sequence
+from typing import Any, Dict, List, Mapping, Sequence
import markdown
from django.utils.html import escape as escape_html
@@ -36,6 +36,13 @@ OBJECT_DETAILS_TEMPLATE = """
""".strip()
+ONEOF_OBJECT_DETAILS_TEMPLATE = """
+
An object with the following fields:
+
+""".strip()
+
OBJECT_LIST_ITEM_TEMPLATE = """
{value}: {data_type} {required} {description}{object_details}
@@ -49,6 +56,17 @@ OBJECT_DESCRIPTION_TEMPLATE = """
OBJECT_CODE_TEMPLATE = "{value}".strip()
+ONEOF_DETAILS_TEMPLATE = """
+This parameter must be one of the following:
+
+{values}
+
+""".strip()
+
+ONEOF_LIST_ITEM_TEMPLATE = """
+{item}
+""".strip()
+
class MarkdownArgumentsTableGenerator(Extension):
@override
@@ -100,6 +118,24 @@ class APIArgumentsTablePreprocessor(Preprocessor):
done = True
return lines
+ def render_oneof_block(self, object_schema: Dict[str, Any], name: str) -> str:
+ md_engine = markdown.Markdown(extensions=[])
+ content = ""
+ for element in object_schema["oneOf"]:
+ if "items" in element and "properties" in element["items"]:
+ content += ONEOF_LIST_ITEM_TEMPLATE.format(
+ item=self.render_object_details(element["items"], str(name), True)
+ )
+ elif "properties" in element:
+ content += ONEOF_LIST_ITEM_TEMPLATE.format(
+ item=self.render_object_details(element, str(name), True)
+ )
+ elif "description" in element:
+ content += ONEOF_LIST_ITEM_TEMPLATE.format(
+ item=md_engine.convert(element["description"])
+ )
+ return ONEOF_DETAILS_TEMPLATE.format(values=content)
+
def render_parameters(self, parameters: Sequence[Parameter]) -> List[str]:
lines = []
@@ -159,6 +195,8 @@ class APIArgumentsTablePreprocessor(Preprocessor):
object_block = self.render_object_details(object_schema["items"], str(name))
elif "properties" in object_schema:
object_block = self.render_object_details(object_schema, str(name))
+ elif "oneOf" in object_schema:
+ object_block = self.render_oneof_block(object_schema, str(name))
lines.append(
API_PARAMETER_TEMPLATE.format(
@@ -174,7 +212,9 @@ class APIArgumentsTablePreprocessor(Preprocessor):
return lines
- def render_object_details(self, schema: Mapping[str, Any], name: str) -> str:
+ def render_object_details(
+ self, schema: Mapping[str, Any], name: str, oneof: bool = False
+ ) -> str:
md_engine = markdown.Markdown(extensions=[])
li_elements = []
@@ -227,6 +267,8 @@ class APIArgumentsTablePreprocessor(Preprocessor):
details = ""
if "object" in data_type and "properties" in object_values[value]:
details += self.render_object_details(object_values[value], str(value))
+ elif "oneOf" in object_values[value]:
+ details += self.render_oneof_block(object_values[value], str(value))
li = OBJECT_LIST_ITEM_TEMPLATE.format(
value=value,
@@ -237,11 +279,15 @@ class APIArgumentsTablePreprocessor(Preprocessor):
)
li_elements.append(li)
-
- object_details = OBJECT_DETAILS_TEMPLATE.format(
- argument=name,
- values="\n".join(li_elements),
- )
+ if oneof:
+ object_details = ONEOF_OBJECT_DETAILS_TEMPLATE.format(
+ values="\n".join(li_elements),
+ )
+ else:
+ object_details = OBJECT_DETAILS_TEMPLATE.format(
+ argument=name,
+ values="\n".join(li_elements),
+ )
return object_details
diff --git a/zerver/lib/markdown/api_return_values_table_generator.py b/zerver/lib/markdown/api_return_values_table_generator.py
index 9d98bcdad0..97a6a91974 100644
--- a/zerver/lib/markdown/api_return_values_table_generator.py
+++ b/zerver/lib/markdown/api_return_values_table_generator.py
@@ -147,6 +147,39 @@ class APIReturnValuesTablePreprocessor(Preprocessor):
+ description
)
+ def render_oneof_block(self, object_schema: Dict[str, Any], spacing: int) -> List[str]:
+ ans = []
+ block_spacing = spacing
+ for element in object_schema["oneOf"]:
+ spacing = block_spacing
+ if "description" not in element:
+ # If the description is not present, we still need to render the rest
+ # of the documentation of the element shifted towards left of the page.
+ spacing -= 4
+ else:
+ # Add the specialized description of the oneOf element.
+ data_type = generate_data_type(element)
+ ans.append(self.render_desc(element["description"], spacing, data_type))
+ # If the oneOf element is an object schema then render the documentation
+ # of its keys.
+ if "properties" in element:
+ ans += self.render_table(element["properties"], spacing + 4)
+ if element.get("additionalProperties", False):
+ additional_properties = element["additionalProperties"]
+ if "description" in additional_properties:
+ data_type = generate_data_type(additional_properties)
+ ans.append(
+ self.render_desc(
+ additional_properties["description"], spacing + 4, data_type
+ )
+ )
+ if "properties" in additional_properties:
+ ans += self.render_table(
+ additional_properties["properties"],
+ spacing + 8,
+ )
+ return ans
+
def render_table(self, return_values: Dict[str, Any], spacing: int) -> List[str]:
IGNORE = ["result", "msg", "ignored_parameters_unsupported"]
ans = []
@@ -165,16 +198,7 @@ class APIReturnValuesTablePreprocessor(Preprocessor):
return_values[return_value]["description"], spacing, data_type, return_value
)
)
- for element in return_values[return_value]["oneOf"]:
- if "description" not in element:
- continue
- # Add the specialized description of the oneOf element.
- data_type = generate_data_type(element)
- ans.append(self.render_desc(element["description"], spacing + 4, data_type))
- # If the oneOf element is an object schema then render the documentation
- # of its keys.
- if "properties" in element:
- ans += self.render_table(element["properties"], spacing + 8)
+ ans += self.render_oneof_block(return_values[return_value], spacing + 4)
continue
description = return_values[return_value]["description"]
data_type = generate_data_type(return_values[return_value])
@@ -198,6 +222,10 @@ class APIReturnValuesTablePreprocessor(Preprocessor):
return_values[return_value]["additionalProperties"]["properties"],
spacing + 8,
)
+ elif "oneOf" in return_values[return_value]["additionalProperties"]:
+ ans += self.render_oneof_block(
+ return_values[return_value]["additionalProperties"], spacing + 8
+ )
elif return_values[return_value]["additionalProperties"].get(
"additionalProperties", False
):
@@ -220,13 +248,15 @@ class APIReturnValuesTablePreprocessor(Preprocessor):
],
spacing + 12,
)
- if (
- "items" in return_values[return_value]
- and "properties" in return_values[return_value]["items"]
- ):
- ans += self.render_table(
- return_values[return_value]["items"]["properties"], spacing + 4
- )
+ if "items" in return_values[return_value]:
+ if "properties" in return_values[return_value]["items"]:
+ ans += self.render_table(
+ return_values[return_value]["items"]["properties"], spacing + 4
+ )
+ elif "oneOf" in return_values[return_value]["items"]:
+ ans += self.render_oneof_block(
+ return_values[return_value]["items"], spacing + 4
+ )
return ans
def generate_event_strings(self, event_data: EventData) -> List[str]: