mirror of https://github.com/zulip/zulip.git
openapi: Make base class for Markdown Preprocessors.
Most of the Markdown Preprocessors followed a common template, and the `run` and `init` code was duplicated multiple times for different preprocessors. This commit adds a base class from which the preprocessors following the pattern can inherit, and can override the `render` and `generate_text` functions to execute the code.
This commit is contained in:
parent
f377f8a963
commit
989d14299c
|
@ -10,7 +10,7 @@ import json
|
||||||
import re
|
import re
|
||||||
import shlex
|
import shlex
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
from typing import Any, Dict, List, Mapping, Optional, Pattern, Tuple
|
from typing import Any, Dict, List, Mapping, Match, Optional, Pattern, Tuple
|
||||||
|
|
||||||
import markdown
|
import markdown
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -435,19 +435,52 @@ class APIMarkdownExtension(Extension):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class APICodeExamplesPreprocessor(Preprocessor):
|
class BasePreprocessor(Preprocessor):
|
||||||
def __init__(self, md: markdown.Markdown, config: Mapping[str, Any]) -> None:
|
def __init__(
|
||||||
|
self, REGEXP: Pattern[str], md: markdown.Markdown, config: Mapping[str, Any]
|
||||||
|
) -> None:
|
||||||
super().__init__(md)
|
super().__init__(md)
|
||||||
self.api_url = config["api_url"]
|
self.api_url = config["api_url"]
|
||||||
|
self.REGEXP = REGEXP
|
||||||
|
|
||||||
def run(self, lines: List[str]) -> List[str]:
|
def run(self, lines: List[str]) -> List[str]:
|
||||||
done = False
|
done = False
|
||||||
while not done:
|
while not done:
|
||||||
for line in lines:
|
for line in lines:
|
||||||
loc = lines.index(line)
|
loc = lines.index(line)
|
||||||
match = MACRO_REGEXP.search(line)
|
match = self.REGEXP.search(line)
|
||||||
|
|
||||||
if match:
|
if match:
|
||||||
|
text = self.generate_text(match)
|
||||||
|
|
||||||
|
# The line that contains the directive to include the macro
|
||||||
|
# may be preceded or followed by text or tags, in that case
|
||||||
|
# we need to make sure that any preceding or following text
|
||||||
|
# stays the same.
|
||||||
|
line_split = self.REGEXP.split(line, maxsplit=0)
|
||||||
|
preceding = line_split[0]
|
||||||
|
following = line_split[-1]
|
||||||
|
text = [preceding, *text, following]
|
||||||
|
lines = lines[:loc] + text + lines[loc + 1 :]
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
done = True
|
||||||
|
return lines
|
||||||
|
|
||||||
|
def generate_text(self, match: Match[str]) -> List[str]:
|
||||||
|
function = match.group(2)
|
||||||
|
text = self.render(function)
|
||||||
|
return text
|
||||||
|
|
||||||
|
def render(self, function: str) -> List[str]:
|
||||||
|
raise NotImplementedError("Must be overriden by a child class")
|
||||||
|
|
||||||
|
|
||||||
|
class APICodeExamplesPreprocessor(BasePreprocessor):
|
||||||
|
def __init__(self, md: markdown.Markdown, config: Mapping[str, Any]) -> None:
|
||||||
|
super().__init__(MACRO_REGEXP, md, config)
|
||||||
|
|
||||||
|
def generate_text(self, match: Match[str]) -> List[str]:
|
||||||
language, options = parse_language_and_options(match.group(2))
|
language, options = parse_language_and_options(match.group(2))
|
||||||
function = match.group(3)
|
function = match.group(3)
|
||||||
key = match.group(4)
|
key = match.group(4)
|
||||||
|
@ -456,67 +489,25 @@ class APICodeExamplesPreprocessor(Preprocessor):
|
||||||
options["api_url"] = self.api_url
|
options["api_url"] = self.api_url
|
||||||
|
|
||||||
if key == "fixture":
|
if key == "fixture":
|
||||||
text = self.render_fixture(function)
|
text = self.render(function)
|
||||||
elif key == "example":
|
elif key == "example":
|
||||||
path, method = function.rsplit(":", 1)
|
path, method = function.rsplit(":", 1)
|
||||||
if language in ADMIN_CONFIG_LANGUAGES and check_requires_administrator(
|
if language in ADMIN_CONFIG_LANGUAGES and check_requires_administrator(path, method):
|
||||||
path, method
|
text = SUPPORTED_LANGUAGES[language]["render"](function, admin_config=True)
|
||||||
):
|
|
||||||
text = SUPPORTED_LANGUAGES[language]["render"](
|
|
||||||
function, admin_config=True
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
text = SUPPORTED_LANGUAGES[language]["render"](function, **options)
|
text = SUPPORTED_LANGUAGES[language]["render"](function, **options)
|
||||||
|
return text
|
||||||
|
|
||||||
# The line that contains the directive to include the macro
|
def render(self, function: str) -> List[str]:
|
||||||
# may be preceded or followed by text or tags, in that case
|
|
||||||
# we need to make sure that any preceding or following text
|
|
||||||
# stays the same.
|
|
||||||
line_split = MACRO_REGEXP.split(line, maxsplit=0)
|
|
||||||
preceding = line_split[0]
|
|
||||||
following = line_split[-1]
|
|
||||||
text = [preceding, *text, following]
|
|
||||||
lines = lines[:loc] + text + lines[loc + 1 :]
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
done = True
|
|
||||||
return lines
|
|
||||||
|
|
||||||
def render_fixture(self, function: str) -> List[str]:
|
|
||||||
path, method = function.rsplit(":", 1)
|
path, method = function.rsplit(":", 1)
|
||||||
return generate_openapi_fixture(path, method)
|
return generate_openapi_fixture(path, method)
|
||||||
|
|
||||||
|
|
||||||
class APIDescriptionPreprocessor(Preprocessor):
|
class APIDescriptionPreprocessor(BasePreprocessor):
|
||||||
def __init__(self, md: markdown.Markdown, config: Mapping[str, Any]) -> None:
|
def __init__(self, md: markdown.Markdown, config: Mapping[str, Any]) -> None:
|
||||||
super().__init__(md)
|
super().__init__(MACRO_REGEXP_DESC, md, config)
|
||||||
self.api_url = config["api_url"]
|
|
||||||
|
|
||||||
def run(self, lines: List[str]) -> List[str]:
|
def render(self, function: str) -> List[str]:
|
||||||
done = False
|
|
||||||
while not done:
|
|
||||||
for line in lines:
|
|
||||||
loc = lines.index(line)
|
|
||||||
match = MACRO_REGEXP_DESC.search(line)
|
|
||||||
|
|
||||||
if match:
|
|
||||||
function = match.group(2)
|
|
||||||
text = self.render_description(function)
|
|
||||||
# The line that contains the directive to include the macro
|
|
||||||
# may be preceded or followed by text or tags, in that case
|
|
||||||
# we need to make sure that any preceding or following text
|
|
||||||
# stays the same.
|
|
||||||
line_split = MACRO_REGEXP_DESC.split(line, maxsplit=0)
|
|
||||||
preceding = line_split[0]
|
|
||||||
following = line_split[-1]
|
|
||||||
text = [preceding, *text, following]
|
|
||||||
lines = lines[:loc] + text + lines[loc + 1 :]
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
done = True
|
|
||||||
return lines
|
|
||||||
|
|
||||||
def render_description(self, function: str) -> List[str]:
|
|
||||||
description: List[str] = []
|
description: List[str] = []
|
||||||
path, method = function.rsplit(":", 1)
|
path, method = function.rsplit(":", 1)
|
||||||
description_dict = get_openapi_description(path, method)
|
description_dict = get_openapi_description(path, method)
|
||||||
|
@ -525,36 +516,11 @@ class APIDescriptionPreprocessor(Preprocessor):
|
||||||
return description
|
return description
|
||||||
|
|
||||||
|
|
||||||
class APITitlePreprocessor(Preprocessor):
|
class APITitlePreprocessor(BasePreprocessor):
|
||||||
def __init__(self, md: markdown.Markdown, config: Mapping[str, Any]) -> None:
|
def __init__(self, md: markdown.Markdown, config: Mapping[str, Any]) -> None:
|
||||||
super().__init__(md)
|
super().__init__(MACRO_REGEXP_TITLE, md, config)
|
||||||
self.api_url = config["api_url"]
|
|
||||||
|
|
||||||
def run(self, lines: List[str]) -> List[str]:
|
def render(self, function: str) -> List[str]:
|
||||||
done = False
|
|
||||||
while not done:
|
|
||||||
for line in lines:
|
|
||||||
loc = lines.index(line)
|
|
||||||
match = MACRO_REGEXP_TITLE.search(line)
|
|
||||||
|
|
||||||
if match:
|
|
||||||
function = match.group(2)
|
|
||||||
text = self.render_title(function)
|
|
||||||
# The line that contains the directive to include the macro
|
|
||||||
# may be preceded or followed by text or tags, in that case
|
|
||||||
# we need to make sure that any preceding or following text
|
|
||||||
# stays the same.
|
|
||||||
line_split = MACRO_REGEXP_TITLE.split(line, maxsplit=0)
|
|
||||||
preceding = line_split[0]
|
|
||||||
following = line_split[-1]
|
|
||||||
text = [preceding, *text, following]
|
|
||||||
lines = lines[:loc] + text + lines[loc + 1 :]
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
done = True
|
|
||||||
return lines
|
|
||||||
|
|
||||||
def render_title(self, function: str) -> List[str]:
|
|
||||||
title: List[str] = []
|
title: List[str] = []
|
||||||
path, method = function.rsplit(":", 1)
|
path, method = function.rsplit(":", 1)
|
||||||
raw_title = get_openapi_summary(path, method)
|
raw_title = get_openapi_summary(path, method)
|
||||||
|
@ -565,36 +531,11 @@ class APITitlePreprocessor(Preprocessor):
|
||||||
return title
|
return title
|
||||||
|
|
||||||
|
|
||||||
class ResponseDescriptionPreprocessor(Preprocessor):
|
class ResponseDescriptionPreprocessor(BasePreprocessor):
|
||||||
def __init__(self, md: markdown.Markdown, config: Mapping[str, Any]) -> None:
|
def __init__(self, md: markdown.Markdown, config: Mapping[str, Any]) -> None:
|
||||||
super().__init__(md)
|
super().__init__(MACRO_REGEXP_RESPONSE_DESC, md, config)
|
||||||
self.api_url = config["api_url"]
|
|
||||||
|
|
||||||
def run(self, lines: List[str]) -> List[str]:
|
def render(self, function: str) -> List[str]:
|
||||||
done = False
|
|
||||||
while not done:
|
|
||||||
for line in lines:
|
|
||||||
loc = lines.index(line)
|
|
||||||
match = MACRO_REGEXP_RESPONSE_DESC.search(line)
|
|
||||||
|
|
||||||
if match:
|
|
||||||
function = match.group(2)
|
|
||||||
text = self.render_responses_description(function)
|
|
||||||
# The line that contains the directive to include the macro
|
|
||||||
# may be preceded or followed by text or tags, in that case
|
|
||||||
# we need to make sure that any preceding or following text
|
|
||||||
# stays the same.
|
|
||||||
line_split = MACRO_REGEXP_RESPONSE_DESC.split(line, maxsplit=0)
|
|
||||||
preceding = line_split[0]
|
|
||||||
following = line_split[-1]
|
|
||||||
text = [preceding, *text, following]
|
|
||||||
lines = lines[:loc] + text + lines[loc + 1 :]
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
done = True
|
|
||||||
return lines
|
|
||||||
|
|
||||||
def render_responses_description(self, function: str) -> List[str]:
|
|
||||||
description: List[str] = []
|
description: List[str] = []
|
||||||
path, method = function.rsplit(":", 1)
|
path, method = function.rsplit(":", 1)
|
||||||
raw_description = get_responses_description(path, method)
|
raw_description = get_responses_description(path, method)
|
||||||
|
@ -602,36 +543,11 @@ class ResponseDescriptionPreprocessor(Preprocessor):
|
||||||
return description
|
return description
|
||||||
|
|
||||||
|
|
||||||
class ParameterDescriptionPreprocessor(Preprocessor):
|
class ParameterDescriptionPreprocessor(BasePreprocessor):
|
||||||
def __init__(self, md: markdown.Markdown, config: Mapping[str, Any]) -> None:
|
def __init__(self, md: markdown.Markdown, config: Mapping[str, Any]) -> None:
|
||||||
super().__init__(md)
|
super().__init__(MACRO_REGEXP_PARAMETER_DESC, md, config)
|
||||||
self.api_url = config["api_url"]
|
|
||||||
|
|
||||||
def run(self, lines: List[str]) -> List[str]:
|
def render(self, function: str) -> List[str]:
|
||||||
done = False
|
|
||||||
while not done:
|
|
||||||
for line in lines:
|
|
||||||
loc = lines.index(line)
|
|
||||||
match = MACRO_REGEXP_PARAMETER_DESC.search(line)
|
|
||||||
|
|
||||||
if match:
|
|
||||||
function = match.group(2)
|
|
||||||
text = self.render_parameters_description(function)
|
|
||||||
# The line that contains the directive to include the macro
|
|
||||||
# may be preceded or followed by text or tags, in that case
|
|
||||||
# we need to make sure that any preceding or following text
|
|
||||||
# stays the same.
|
|
||||||
line_split = MACRO_REGEXP_PARAMETER_DESC.split(line, maxsplit=0)
|
|
||||||
preceding = line_split[0]
|
|
||||||
following = line_split[-1]
|
|
||||||
text = [preceding, *text, following]
|
|
||||||
lines = lines[:loc] + text + lines[loc + 1 :]
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
done = True
|
|
||||||
return lines
|
|
||||||
|
|
||||||
def render_parameters_description(self, function: str) -> List[str]:
|
|
||||||
description: List[str] = []
|
description: List[str] = []
|
||||||
path, method = function.rsplit(":", 1)
|
path, method = function.rsplit(":", 1)
|
||||||
raw_description = get_parameters_description(path, method)
|
raw_description = get_parameters_description(path, method)
|
||||||
|
|
Loading…
Reference in New Issue