from .util import escape, escape_html
class BaseRenderer(object):
NAME = 'base'
def __init__(self):
self._methods = {}
def register(self, name, method):
self._methods[name] = method
def _get_method(self, name):
try:
return object.__getattribute__(self, name)
except AttributeError:
method = self._methods.get(name)
if not method:
raise AttributeError('No renderer "{!r}"'.format(name))
return method
def finalize(self, data):
raise NotImplementedError(
'The renderer needs to implement the finalize method.')
class AstRenderer(BaseRenderer):
NAME = 'ast'
def text(self, text):
return {'type': 'text', 'text': text}
def link(self, link, children=None, title=None):
if isinstance(children, str):
children = [{'type': 'text', 'text': children}]
return {
'type': 'link',
'link': link,
'children': children,
'title': title,
}
def image(self, src, alt="", title=None):
return {'type': 'image', 'src': src, 'alt': alt, 'title': title}
def codespan(self, text):
return {'type': 'codespan', 'text': text}
def linebreak(self):
return {'type': 'linebreak'}
def inline_html(self, html):
return {'type': 'inline_html', 'text': html}
def heading(self, children, level):
return {'type': 'heading', 'children': children, 'level': level}
def newline(self):
return {'type': 'newline'}
def thematic_break(self):
return {'type': 'thematic_break'}
def block_code(self, children, info=None):
return {
'type': 'block_code',
'text': children,
'info': info
}
def block_html(self, children):
return {'type': 'block_html', 'text': children}
def list(self, children, ordered, level, start=None):
token = {
'type': 'list',
'children': children,
'ordered': ordered,
'level': level,
}
if start is not None:
token['start'] = start
return token
def list_item(self, children, level):
return {'type': 'list_item', 'children': children, 'level': level}
def _create_default_method(self, name):
def __ast(children):
return {'type': name, 'children': children}
return __ast
def _get_method(self, name):
try:
return super(AstRenderer, self)._get_method(name)
except AttributeError:
return self._create_default_method(name)
def finalize(self, data):
return list(data)
class HTMLRenderer(BaseRenderer):
NAME = 'html'
HARMFUL_PROTOCOLS = {
'javascript:',
'vbscript:',
'data:',
}
def __init__(self, escape=True, allow_harmful_protocols=None):
super(HTMLRenderer, self).__init__()
self._escape = escape
self._allow_harmful_protocols = allow_harmful_protocols
def _safe_url(self, url):
if self._allow_harmful_protocols is None:
schemes = self.HARMFUL_PROTOCOLS
elif self._allow_harmful_protocols is True:
schemes = None
else:
allowed = set(self._allow_harmful_protocols)
schemes = self.HARMFUL_PROTOCOLS - allowed
if schemes:
for s in schemes:
if url.lower().startswith(s):
url = '#harmful-link'
break
return url
def text(self, text):
if self._escape:
return escape(text)
return escape_html(text)
def link(self, link, text=None, title=None):
if text is None:
text = link
s = '' + (text or link) + ''
def image(self, src, alt="", title=None):
src = self._safe_url(src)
alt = escape_html(alt)
s = ''
def emphasis(self, text):
return '' + text + ''
def strong(self, text):
return '' + text + ''
def codespan(self, text):
return '' + escape(text) + '
'
def linebreak(self):
return '
\n'
def inline_html(self, html):
if self._escape:
return escape(html)
return html
def paragraph(self, text):
return '
' + text + '
\n' def heading(self, text, level): tag = 'h' + str(level) return '<' + tag + '>' + text + '' + tag + '>\n' def newline(self): return '' def thematic_break(self): return '' + escape(code) + '
\n'
def block_quote(self, text):
return '\n' + text + '\n' def block_html(self, html): if not self._escape: return html + '\n' return '
' + escape(html) + '
\n' def block_error(self, html): return '