Skip to content

Commit 3cb32df

Browse files
committed
Revert "Change from Preprocessor to BlockProcessor"
This reverts commit 9caa70e.
1 parent 9caa70e commit 3cb32df

File tree

1 file changed

+77
-60
lines changed

1 file changed

+77
-60
lines changed

src/markdown_mermaid_data_uri/extension.py

Lines changed: 77 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -2,75 +2,89 @@
22

33
import base64
44
import os
5-
import re
65
import shutil
76
import subprocess
87
import tempfile
9-
import xml.etree.ElementTree as etree
8+
from typing import List
109

1110
import requests
1211
from markdown import Extension
13-
from markdown.blockprocessors import BlockProcessor
12+
from markdown.preprocessors import Preprocessor
1413

1514

16-
class MermaidDataURIProcessor(BlockProcessor):
15+
class MermaidDataURIPreprocessor(Preprocessor):
1716
"""Preprocessor to convert mermaid code blocks to SVG/PNG images."""
1817

19-
MERMAID_CODE_BLOCK_RE = re.compile(r'```mermaid\s*(.*)')
20-
MIME_TYPES = {
21-
'svg': 'image/svg+xml',
22-
'png': 'image/png',
23-
}
24-
25-
def test(self, parent, block):
26-
return self.MERMAID_CODE_BLOCK_RE.match(block)
27-
28-
def __init__(self, parser, kroki_url, mermaid_cli):
29-
super().__init__(parser)
30-
self.kroki_url = kroki_url
31-
self.mermaid_cli = mermaid_cli
32-
33-
def run(self, parent, blocks):
34-
# Mermaid code block
35-
block = blocks.pop(0)
36-
match = self.MERMAID_CODE_BLOCK_RE.match(block)
37-
mermaid_code = block[match.end() :].strip().replace('```', '').strip()
38-
39-
# Options
40-
options_str = match.group(1).strip()
41-
options = {}
42-
if options_str:
43-
for item in options_str.split():
44-
if '=' in item:
45-
key, value = item.split('=', 1)
46-
options[key] = value.strip('"\'')
47-
48-
# Data URI
49-
data_uri = self._get_data_uri(mermaid_code, options)
50-
51-
# Create image element
52-
el = etree.SubElement(parent, 'p')
53-
img = etree.SubElement(el, 'img', {'src': data_uri})
54-
img.text = mermaid_code
55-
del options['image']
56-
for key, value in options.items():
57-
img.set(key, value)
58-
59-
def _get_data_uri(self, content: str, options: dict) -> str:
60-
"""Convert mermaid code to data URI."""
61-
image_type = options.get('image', 'svg')
62-
base64image = self._get_base64image(content, image_type)
63-
data_uri = f'data:{self.MIME_TYPES[image_type]};base64,{base64image}'
64-
return data_uri
65-
66-
def _get_base64image(self, mermaid_code: str, image_type: str) -> str:
18+
KROKI_URL = 'https://kroki.io'
19+
20+
def __init__(self, md, config):
21+
super().__init__(md)
22+
self.kroki_url = config.get('kroki_url', self.KROKI_URL)
23+
self.mermaid_cli = config.get('mermaid_cli', False)
24+
25+
def run(self, lines: List[str]) -> List[str]:
26+
new_lines: List[str] = []
27+
is_in_mermaid = False
28+
29+
for line in lines:
30+
if line.strip().startswith('```mermaid'):
31+
is_in_mermaid = True
32+
mermaid_block: List[str] = []
33+
# Extract options after '```mermaid'
34+
options = line.strip()[10:].strip()
35+
option_dict = {}
36+
if options:
37+
for option in options.split():
38+
key, _, value = option.partition('=')
39+
option_dict[key] = value
40+
continue
41+
elif line.strip() == '```' and is_in_mermaid:
42+
is_in_mermaid = False
43+
if mermaid_block:
44+
mermaid_code = '\n'.join(mermaid_block)
45+
46+
# Image type handling
47+
if 'image' in option_dict:
48+
image_type = option_dict['image']
49+
del option_dict['image']
50+
if image_type not in ['svg', 'png']:
51+
image_type = 'svg'
52+
else:
53+
image_type = 'svg'
54+
55+
base64image = self._mermaid2base64image(mermaid_code, image_type)
56+
if base64image:
57+
# Build the <img> tag with extracted options
58+
if image_type == 'svg':
59+
img_tag = f'<img src="data:image/svg+xml;base64,{base64image}"'
60+
else:
61+
img_tag = f'<img src="data:image/png;base64,{base64image}"'
62+
for key, value in option_dict.items():
63+
img_tag += f' {key}={value}'
64+
img_tag += ' />'
65+
new_lines.append(img_tag)
66+
else:
67+
new_lines.append('```mermaid')
68+
new_lines.extend(mermaid_block)
69+
new_lines.append('```')
70+
continue
71+
72+
if is_in_mermaid:
73+
mermaid_block.append(line)
74+
else:
75+
new_lines.append(line)
76+
77+
return new_lines
78+
79+
def _mermaid2base64image(self, mermaid_code: str, image_type: str) -> str:
6780
"""Convert mermaid code to SVG/PNG."""
81+
# Use Kroki or mmdc (Mermaid CLI) to convert mermaid code to image
6882
if not self.mermaid_cli:
69-
return self._get_base64image_from_kroki(mermaid_code, image_type)
83+
return self._mermaid2base64image_kroki(mermaid_code, image_type)
7084
else:
71-
return self._get_base64image_from_mmdc(mermaid_code, image_type)
85+
return self._mermaid2base64image_mmdc(mermaid_code, image_type)
7286

73-
def _get_base64image_from_kroki(self, mermaid_code: str, image_type: str) -> str:
87+
def _mermaid2base64image_kroki(self, mermaid_code: str, image_type: str) -> str:
7488
"""Convert mermaid code to SVG/PNG using Kroki."""
7589
kroki_url = f'{self.kroki_url}/mermaid/{image_type}'
7690
headers = {'Content-Type': 'text/plain'}
@@ -86,7 +100,7 @@ def _get_base64image_from_kroki(self, mermaid_code: str, image_type: str) -> str
86100
return base64image
87101
return ''
88102

89-
def _get_base64image_from_mmdc(self, mermaid_code: str, image_type: str) -> str:
103+
def _mermaid2base64image_mmdc(self, mermaid_code: str, image_type: str) -> str:
90104
"""Convert mermaid code to SVG/PNG using mmdc (Mermaid CLI)."""
91105
with tempfile.NamedTemporaryFile(mode='w', suffix='.mmd', delete=False) as tmp_mmd:
92106
tmp_mmd.write(mermaid_code)
@@ -138,14 +152,17 @@ class MermaidDataURIExtension(Extension):
138152

139153
def __init__(self, **kwargs):
140154
self.config = {
141-
'kroki_url': [kwargs.get('kroki_url', 'https://kroki.io'), 'Kroki server URL'],
142-
'mermaid_cli': [kwargs.get('mermaid_cli', False), 'Use mermaid CLI (requires installation)'],
155+
'kroki_url': ['https://kroki.io', 'Base URL for the Kroki server.'],
156+
'mermaid_cli': [False, 'Use mmdc (Mermaid CLI) instead of Kroki server.'],
143157
}
144158
super().__init__(**kwargs)
159+
self.extension_configs = kwargs
145160

146161
def extendMarkdown(self, md):
147-
self.processor = MermaidDataURIProcessor(md.parser, self.getConfig('kroki_url'), self.getConfig('mermaid_cli'))
148-
md.parser.blockprocessors.register(self.processor, 'markdown_mermaid_data_uri', 50)
162+
config = self.getConfigs()
163+
final_config = {**config, **self.extension_configs}
164+
mermaid_preprocessor = MermaidDataURIPreprocessor(md, final_config)
165+
md.preprocessors.register(mermaid_preprocessor, 'markdown_mermaid_data_udi', 50)
149166

150167

151168
# pylint: disable=C0103

0 commit comments

Comments
 (0)