From b285e631e9e7db59d687e2356f967aa7485ec532 Mon Sep 17 00:00:00 2001 From: Vector73 Date: Thu, 20 Jun 2024 19:39:32 +0530 Subject: [PATCH] api_docs: Fix missing content from API documentation. --- .../markdown/api_arguments_table_generator.py | 60 +++++++++++++++-- .../api_return_values_table_generator.py | 64 ++++++++++++++----- 2 files changed, 100 insertions(+), 24 deletions(-) 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]: