aboutsummaryrefslogtreecommitdiff
path: root/mammoth
diff options
context:
space:
mode:
authorMichael Williamson <mike@zwobble.org>2026-09-26 22:46:13 +0100
committerMichael Williamson <mike@zwobble.org>2026-09-26 22:46:13 +0100
commit2a5cf02b98fe7d20ba7af5395f0af1f22e2c4210 (patch)
tree722cebf5ce50926fe767386978efde9e82adab91 /mammoth
parentaa2253a10d92a07af74e96a04568734dc4c197f1 (diff)
Escape HTML IDs in markdown writer
Diffstat (limited to 'mammoth')
-rw-r--r--mammoth/writers/markdown.py60
1 files changed, 32 insertions, 28 deletions
diff --git a/mammoth/writers/markdown.py b/mammoth/writers/markdown.py
index 6cd9cd0..c78fd3f 100644
--- a/mammoth/writers/markdown.py
+++ b/mammoth/writers/markdown.py
@@ -1,6 +1,7 @@
from __future__ import unicode_literals
from .abc import Writer
+from . import html
import re
@@ -9,7 +10,7 @@ class _WriterOutput(object):
def __init__(self, start, end=None, generate_end=None, anchor_position=None):
if generate_end is None:
generate_end = _constant(end)
-
+
self.start = start
self.generate_end = generate_end
self.anchor_position = anchor_position
@@ -18,7 +19,7 @@ class _WriterOutput(object):
def _constant(value):
def get():
return value
-
+
return get
@@ -27,11 +28,11 @@ class _MarkdownState(object):
self._list_state_stack = []
self.list_state = None
self.list_item_has_closed = False
-
+
def update_list_state(self, list_state):
self._list_state_stack.append(self.list_state)
self.list_state = list_state
-
+
def pop_list_state(self):
self.list_state = self._list_state_stack.pop()
@@ -51,7 +52,7 @@ class _Wrapped(object):
def __init__(self, start, end):
self._start = start
self._end = end
-
+
def __call__(self, attributes, markdown_state):
return _WriterOutput(self._start, self._end)
@@ -86,39 +87,39 @@ def _list(ordered):
start = "\n"
end_text = ""
indentation = markdown_state.list_state.indentation + 1
-
+
def generate_end():
markdown_state.pop_list_state()
return end_text
-
+
markdown_state.update_list_state(_MarkdownListState(
ordered=ordered,
indentation=indentation,
))
-
+
return _WriterOutput(start, generate_end=generate_end)
-
+
return call
def _list_item(attributes, markdown_state):
markdown_state.list_item_has_closed = False
-
+
list_state = markdown_state.list_state or _MarkdownListState(ordered=False, indentation=0)
list_state.count += 1
-
+
if list_state.ordered:
bullet = "{0}.".format(list_state.count)
else:
bullet = "-"
-
+
def generate_end():
if markdown_state.list_item_has_closed:
return ""
else:
markdown_state.list_item_has_closed = True
return "\n"
-
+
return _WriterOutput(
start=("\t" * list_state.indentation) + bullet + " ",
generate_end=generate_end
@@ -137,10 +138,10 @@ def _init_writers():
"ul": _list(ordered=False),
"li": _list_item,
}
-
+
for level in range(1, 7):
writers["h{0}".format(level)] = _Wrapped("#" * level + " ", "\n\n")
-
+
return writers
@@ -156,47 +157,50 @@ class MarkdownWriter(Writer):
self._fragments = []
self._element_stack = []
self._markdown_state = _MarkdownState()
-
+
def text(self, text):
self._fragments.append(_escape_markdown(text))
-
+
def start(self, name, attributes=None):
if attributes is None:
attributes = {}
-
+
output = _writers.get(name, _default_writer)(attributes, self._markdown_state)
self._element_stack.append(output.generate_end)
-
+
anchor_before_start = output.anchor_position == "before"
if anchor_before_start:
self._write_anchor(attributes)
-
+
self._fragments.append(output.start)
-
+
if not anchor_before_start:
self._write_anchor(attributes)
-
-
+
+
def end(self, name):
end = self._element_stack.pop()
output = end()
self._fragments.append(output)
-
+
def self_closing(self, name, attributes=None):
self.start(name, attributes)
self.end(name)
-
+
def append(self, other):
self._fragments.append(other)
-
+
def as_string(self):
return "".join(self._fragments)
-
+
def _write_anchor(self, attributes):
html_id = attributes.get("id")
if html_id:
- self._fragments.append('<a id="{0}"></a>'.format(html_id))
+ writer = html.HtmlWriter()
+ writer.start("a", {"id": html_id})
+ writer.end("a")
+ self._fragments.append(writer.as_string())
def _escape_markdown(value):