Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/mistune/renderers/html.py: 88%

103 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-07-01 06:54 +0000

1from ..core import BaseRenderer 

2from ..util import escape as escape_text, striptags, safe_entity 

3 

4 

5class HTMLRenderer(BaseRenderer): 

6 """A renderer for converting Markdown to HTML.""" 

7 NAME = 'html' 

8 HARMFUL_PROTOCOLS = ( 

9 'javascript:', 

10 'vbscript:', 

11 'file:', 

12 'data:', 

13 ) 

14 GOOD_DATA_PROTOCOLS = ( 

15 'data:image/gif;', 

16 'data:image/png;', 

17 'data:image/jpeg;', 

18 'data:image/webp;', 

19 ) 

20 

21 def __init__(self, escape=True, allow_harmful_protocols=None): 

22 super(HTMLRenderer, self).__init__() 

23 self._allow_harmful_protocols = allow_harmful_protocols 

24 self._escape = escape 

25 

26 def render_token(self, token, state): 

27 # backward compitable with v2 

28 func = self._get_method(token['type']) 

29 attrs = token.get('attrs') 

30 

31 if 'raw' in token: 

32 text = token['raw'] 

33 elif 'children' in token: 

34 text = self.render_tokens(token['children'], state) 

35 else: 

36 if attrs: 

37 return func(**attrs) 

38 else: 

39 return func() 

40 if attrs: 

41 return func(text, **attrs) 

42 else: 

43 return func(text) 

44 

45 def safe_url(self, url: str) -> str: 

46 """Ensure the given URL is safe. This method is used for rendering 

47 links, images, and etc. 

48 """ 

49 if self._allow_harmful_protocols is True: 

50 return url 

51 

52 _url = url.lower() 

53 if self._allow_harmful_protocols and \ 

54 _url.startswith(tuple(self._allow_harmful_protocols)): 

55 return url 

56 

57 if _url.startswith(self.HARMFUL_PROTOCOLS) and \ 

58 not _url.startswith(self.GOOD_DATA_PROTOCOLS): 

59 return '#harmful-link' 

60 return url 

61 

62 def text(self, text: str) -> str: 

63 if self._escape: 

64 return escape_text(text) 

65 return safe_entity(text) 

66 

67 def emphasis(self, text: str) -> str: 

68 return '<em>' + text + '</em>' 

69 

70 def strong(self, text: str) -> str: 

71 return '<strong>' + text + '</strong>' 

72 

73 def link(self, text: str, url: str, title=None) -> str: 

74 s = '<a href="' + self.safe_url(url) + '"' 

75 if title: 

76 s += ' title="' + safe_entity(title) + '"' 

77 return s + '>' + text + '</a>' 

78 

79 def image(self, text: str, url: str, title=None) -> str: 

80 src = self.safe_url(url) 

81 alt = escape_text(striptags(text)) 

82 s = '<img src="' + src + '" alt="' + alt + '"' 

83 if title: 

84 s += ' title="' + safe_entity(title) + '"' 

85 return s + ' />' 

86 

87 def codespan(self, text: str) -> str: 

88 return '<code>' + text + '</code>' 

89 

90 def linebreak(self) -> str: 

91 return '<br />\n' 

92 

93 def softbreak(self) -> str: 

94 return '\n' 

95 

96 def inline_html(self, html: str) -> str: 

97 if self._escape: 

98 return escape_text(html) 

99 return html 

100 

101 def paragraph(self, text: str) -> str: 

102 return '<p>' + text + '</p>\n' 

103 

104 def heading(self, text: str, level: int, **attrs) -> str: 

105 tag = 'h' + str(level) 

106 html = '<' + tag 

107 _id = attrs.get('id') 

108 if _id: 

109 html += ' id="' + _id + '"' 

110 return html + '>' + text + '</' + tag + '>\n' 

111 

112 def blank_line(self) -> str: 

113 return '' 

114 

115 def thematic_break(self) -> str: 

116 return '<hr />\n' 

117 

118 def block_text(self, text: str) -> str: 

119 return text 

120 

121 def block_code(self, code: str, info=None) -> str: 

122 html = '<pre><code' 

123 if info is not None: 

124 info = safe_entity(info.strip()) 

125 if info: 

126 lang = info.split(None, 1)[0] 

127 html += ' class="language-' + lang + '"' 

128 return html + '>' + escape_text(code) + '</code></pre>\n' 

129 

130 def block_quote(self, text: str) -> str: 

131 return '<blockquote>\n' + text + '</blockquote>\n' 

132 

133 def block_html(self, html: str) -> str: 

134 if self._escape: 

135 return '<p>' + escape_text(html.strip()) + '</p>\n' 

136 return html + '\n' 

137 

138 def block_error(self, text: str) -> str: 

139 return '<div class="error"><pre>' + text + '</pre></div>\n' 

140 

141 def list(self, text: str, ordered: bool, **attrs) -> str: 

142 if ordered: 

143 html = '<ol' 

144 start = attrs.get('start') 

145 if start is not None: 

146 html += ' start="' + str(start) + '"' 

147 return html + '>\n' + text + '</ol>\n' 

148 return '<ul>\n' + text + '</ul>\n' 

149 

150 def list_item(self, text: str) -> str: 

151 return '<li>' + text + '</li>\n'