Building Project Files
هذا الالتزام موجود في:
153
venv/lib/python3.12/site-packages/mistune/renderers/html.py
Normal file
153
venv/lib/python3.12/site-packages/mistune/renderers/html.py
Normal file
@@ -0,0 +1,153 @@
|
||||
from typing import Any, ClassVar, Dict, Optional, Tuple, Literal
|
||||
from ..core import BaseRenderer, BlockState
|
||||
from ..util import escape as escape_text
|
||||
from ..util import safe_entity, striptags
|
||||
|
||||
|
||||
class HTMLRenderer(BaseRenderer):
|
||||
"""A renderer for converting Markdown to HTML."""
|
||||
|
||||
_escape: bool
|
||||
NAME: ClassVar[Literal["html"]] = "html"
|
||||
HARMFUL_PROTOCOLS: ClassVar[Tuple[str, ...]] = (
|
||||
"javascript:",
|
||||
"vbscript:",
|
||||
"file:",
|
||||
"data:",
|
||||
)
|
||||
GOOD_DATA_PROTOCOLS: ClassVar[Tuple[str, ...]] = (
|
||||
"data:image/gif;",
|
||||
"data:image/png;",
|
||||
"data:image/jpeg;",
|
||||
"data:image/webp;",
|
||||
)
|
||||
|
||||
def __init__(self, escape: bool = True, allow_harmful_protocols: Optional[bool] = None) -> None:
|
||||
super(HTMLRenderer, self).__init__()
|
||||
self._allow_harmful_protocols = allow_harmful_protocols
|
||||
self._escape = escape
|
||||
|
||||
def render_token(self, token: Dict[str, Any], state: BlockState) -> str:
|
||||
# backward compitable with v2
|
||||
func = self._get_method(token["type"])
|
||||
attrs = token.get("attrs")
|
||||
|
||||
if "raw" in token:
|
||||
text = token["raw"]
|
||||
elif "children" in token:
|
||||
text = self.render_tokens(token["children"], state)
|
||||
else:
|
||||
if attrs:
|
||||
return func(**attrs)
|
||||
else:
|
||||
return func()
|
||||
if attrs:
|
||||
return func(text, **attrs)
|
||||
else:
|
||||
return func(text)
|
||||
|
||||
def safe_url(self, url: str) -> str:
|
||||
"""Ensure the given URL is safe. This method is used for rendering
|
||||
links, images, and etc.
|
||||
"""
|
||||
if self._allow_harmful_protocols is True:
|
||||
return escape_text(url)
|
||||
|
||||
_url = url.lower()
|
||||
if self._allow_harmful_protocols and _url.startswith(tuple(self._allow_harmful_protocols)):
|
||||
return escape_text(url)
|
||||
|
||||
if _url.startswith(self.HARMFUL_PROTOCOLS) and not _url.startswith(self.GOOD_DATA_PROTOCOLS):
|
||||
return "#harmful-link"
|
||||
return escape_text(url)
|
||||
|
||||
def text(self, text: str) -> str:
|
||||
if self._escape:
|
||||
return escape_text(text)
|
||||
return safe_entity(text)
|
||||
|
||||
def emphasis(self, text: str) -> str:
|
||||
return "<em>" + text + "</em>"
|
||||
|
||||
def strong(self, text: str) -> str:
|
||||
return "<strong>" + text + "</strong>"
|
||||
|
||||
def link(self, text: str, url: str, title: Optional[str] = None) -> str:
|
||||
s = '<a href="' + self.safe_url(url) + '"'
|
||||
if title:
|
||||
s += ' title="' + safe_entity(title) + '"'
|
||||
return s + ">" + text + "</a>"
|
||||
|
||||
def image(self, text: str, url: str, title: Optional[str] = None) -> str:
|
||||
src = self.safe_url(url)
|
||||
alt = escape_text(striptags(text))
|
||||
s = '<img src="' + src + '" alt="' + alt + '"'
|
||||
if title:
|
||||
s += ' title="' + safe_entity(title) + '"'
|
||||
return s + " />"
|
||||
|
||||
def codespan(self, text: str) -> str:
|
||||
return "<code>" + escape_text(text) + "</code>"
|
||||
|
||||
def linebreak(self) -> str:
|
||||
return "<br />\n"
|
||||
|
||||
def softbreak(self) -> str:
|
||||
return "\n"
|
||||
|
||||
def inline_html(self, html: str) -> str:
|
||||
if self._escape:
|
||||
return escape_text(html)
|
||||
return html
|
||||
|
||||
def paragraph(self, text: str) -> str:
|
||||
return "<p>" + text + "</p>\n"
|
||||
|
||||
def heading(self, text: str, level: int, **attrs: Any) -> str:
|
||||
tag = "h" + str(level)
|
||||
html = "<" + tag
|
||||
_id = attrs.get("id")
|
||||
if _id:
|
||||
html += ' id="' + _id + '"'
|
||||
return html + ">" + text + "</" + tag + ">\n"
|
||||
|
||||
def blank_line(self) -> str:
|
||||
return ""
|
||||
|
||||
def thematic_break(self) -> str:
|
||||
return "<hr />\n"
|
||||
|
||||
def block_text(self, text: str) -> str:
|
||||
return text
|
||||
|
||||
def block_code(self, code: str, info: Optional[str] = None) -> str:
|
||||
html = "<pre><code"
|
||||
if info is not None:
|
||||
info = safe_entity(info.strip())
|
||||
if info:
|
||||
lang = info.split(None, 1)[0]
|
||||
html += ' class="language-' + lang + '"'
|
||||
return html + ">" + escape_text(code) + "</code></pre>\n"
|
||||
|
||||
def block_quote(self, text: str) -> str:
|
||||
return "<blockquote>\n" + text + "</blockquote>\n"
|
||||
|
||||
def block_html(self, html: str) -> str:
|
||||
if self._escape:
|
||||
return "<p>" + escape_text(html.strip()) + "</p>\n"
|
||||
return html + "\n"
|
||||
|
||||
def block_error(self, text: str) -> str:
|
||||
return '<div class="error"><pre>' + text + "</pre></div>\n"
|
||||
|
||||
def list(self, text: str, ordered: bool, **attrs: Any) -> str:
|
||||
if ordered:
|
||||
html = "<ol"
|
||||
start = attrs.get("start")
|
||||
if start is not None:
|
||||
html += ' start="' + str(start) + '"'
|
||||
return html + ">\n" + text + "</ol>\n"
|
||||
return "<ul>\n" + text + "</ul>\n"
|
||||
|
||||
def list_item(self, text: str) -> str:
|
||||
return "<li>" + text + "</li>\n"
|
المرجع في مشكلة جديدة
حظر مستخدم