markdown-to-confluence 0.5.1__py3-none-any.whl → 0.5.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. {markdown_to_confluence-0.5.1.dist-info → markdown_to_confluence-0.5.3.dist-info}/METADATA +160 -11
  2. markdown_to_confluence-0.5.3.dist-info/RECORD +55 -0
  3. {markdown_to_confluence-0.5.1.dist-info → markdown_to_confluence-0.5.3.dist-info}/licenses/LICENSE +1 -1
  4. md2conf/__init__.py +2 -2
  5. md2conf/__main__.py +94 -29
  6. md2conf/api.py +55 -10
  7. md2conf/attachment.py +72 -0
  8. md2conf/coalesce.py +43 -0
  9. md2conf/collection.py +1 -1
  10. md2conf/{extra.py → compatibility.py} +1 -1
  11. md2conf/converter.py +417 -590
  12. md2conf/csf.py +13 -11
  13. md2conf/drawio/__init__.py +0 -0
  14. md2conf/drawio/extension.py +116 -0
  15. md2conf/{drawio.py → drawio/render.py} +1 -1
  16. md2conf/emoticon.py +3 -3
  17. md2conf/environment.py +2 -2
  18. md2conf/extension.py +78 -0
  19. md2conf/external.py +49 -0
  20. md2conf/formatting.py +135 -0
  21. md2conf/frontmatter.py +70 -0
  22. md2conf/image.py +127 -0
  23. md2conf/latex.py +7 -186
  24. md2conf/local.py +8 -8
  25. md2conf/markdown.py +1 -1
  26. md2conf/matcher.py +1 -1
  27. md2conf/mermaid/__init__.py +0 -0
  28. md2conf/mermaid/config.py +20 -0
  29. md2conf/mermaid/extension.py +109 -0
  30. md2conf/{mermaid.py → mermaid/render.py} +10 -38
  31. md2conf/mermaid/scanner.py +55 -0
  32. md2conf/metadata.py +1 -1
  33. md2conf/options.py +116 -0
  34. md2conf/plantuml/__init__.py +0 -0
  35. md2conf/plantuml/config.py +20 -0
  36. md2conf/plantuml/extension.py +158 -0
  37. md2conf/plantuml/render.py +139 -0
  38. md2conf/plantuml/scanner.py +56 -0
  39. md2conf/png.py +202 -0
  40. md2conf/processor.py +32 -11
  41. md2conf/publisher.py +17 -18
  42. md2conf/scanner.py +31 -128
  43. md2conf/serializer.py +2 -2
  44. md2conf/svg.py +341 -0
  45. md2conf/text.py +1 -1
  46. md2conf/toc.py +1 -1
  47. md2conf/uri.py +1 -1
  48. md2conf/xml.py +1 -1
  49. markdown_to_confluence-0.5.1.dist-info/RECORD +0 -35
  50. md2conf/domain.py +0 -52
  51. {markdown_to_confluence-0.5.1.dist-info → markdown_to_confluence-0.5.3.dist-info}/WHEEL +0 -0
  52. {markdown_to_confluence-0.5.1.dist-info → markdown_to_confluence-0.5.3.dist-info}/entry_points.txt +0 -0
  53. {markdown_to_confluence-0.5.1.dist-info → markdown_to_confluence-0.5.3.dist-info}/top_level.txt +0 -0
  54. {markdown_to_confluence-0.5.1.dist-info → markdown_to_confluence-0.5.3.dist-info}/zip-safe +0 -0
md2conf/svg.py ADDED
@@ -0,0 +1,341 @@
1
+ """
2
+ Publish Markdown files to Confluence wiki.
3
+
4
+ Copyright 2022-2026, Levente Hunyadi
5
+
6
+ :see: https://github.com/hunyadi/md2conf
7
+ """
8
+
9
+ import logging
10
+ import re
11
+ from pathlib import Path
12
+
13
+ import lxml.etree as ET
14
+
15
+ ElementType = ET._Element # pyright: ignore [reportPrivateUsage]
16
+
17
+ LOGGER = logging.getLogger(__name__)
18
+
19
+ SVG_NAMESPACE = "http://www.w3.org/2000/svg"
20
+
21
+
22
+ def _check_svg(root: ElementType) -> bool:
23
+ "Tests if the element is a plain or scoped SVG element."
24
+
25
+ root_tag = root.tag
26
+ if not isinstance(root_tag, str):
27
+ raise TypeError("expected: tag names as `str`")
28
+
29
+ # Handle namespaced and non-namespaced SVG
30
+ qname = ET.QName(root_tag)
31
+ return qname.localname == "svg" and (not qname.namespace or qname.namespace == SVG_NAMESPACE)
32
+
33
+
34
+ def _extract_dimensions_from_root(root: ElementType) -> tuple[int | None, int | None]:
35
+ """
36
+ Extracts width and height from an SVG root element.
37
+
38
+ Attempts to read dimensions from:
39
+ 1. Explicit width/height attributes on the root <svg> element
40
+ 2. The viewBox attribute if width/height are not specified
41
+
42
+ :param root: The root element of the SVG document.
43
+ :returns: A tuple of (width, height) in pixels, or (None, None) if dimensions cannot be determined.
44
+ """
45
+
46
+ if not _check_svg(root):
47
+ return None, None
48
+
49
+ width_attr = root.get("width")
50
+ height_attr = root.get("height")
51
+
52
+ width = _parse_svg_length(width_attr) if width_attr else None
53
+ height = _parse_svg_length(height_attr) if height_attr else None
54
+
55
+ # If width/height not specified, try to derive from viewBox
56
+ if width is None or height is None:
57
+ viewbox = root.get("viewBox")
58
+ if viewbox:
59
+ vb_width, vb_height = _parse_viewbox(viewbox)
60
+ if width is None:
61
+ width = vb_width
62
+ if height is None:
63
+ height = vb_height
64
+
65
+ return width, height
66
+
67
+
68
+ def get_svg_dimensions(path: Path) -> tuple[int | None, int | None]:
69
+ """
70
+ Extracts width and height from an SVG file.
71
+
72
+ Attempts to read dimensions from:
73
+ 1. Explicit width/height attributes on the root <svg> element
74
+ 2. The viewBox attribute if width/height are not specified
75
+
76
+ :param path: Path to the SVG file.
77
+ :returns: A tuple of (width, height) in pixels, or (None, None) if dimensions cannot be determined.
78
+ """
79
+
80
+ try:
81
+ tree = ET.parse(str(path))
82
+ root = tree.getroot()
83
+ width, height = _extract_dimensions_from_root(root)
84
+ if width is None and height is None:
85
+ LOGGER.warning("SVG file %s does not have an <svg> root element", path)
86
+ return width, height
87
+
88
+ except ET.XMLSyntaxError as ex:
89
+ LOGGER.warning("Failed to parse SVG file %s: %s", path, ex)
90
+ return None, None
91
+ except Exception as ex:
92
+ LOGGER.warning("Unexpected error reading SVG dimensions from %s: %s", path, ex)
93
+ return None, None
94
+
95
+
96
+ def get_svg_dimensions_from_bytes(data: bytes) -> tuple[int | None, int | None]:
97
+ """
98
+ Extracts width and height from SVG data in memory.
99
+
100
+ Attempts to read dimensions from:
101
+ 1. Explicit width/height attributes on the root <svg> element
102
+ 2. The viewBox attribute if width/height are not specified
103
+
104
+ :param data: The SVG content as bytes.
105
+ :returns: A tuple of (width, height) in pixels, or (None, None) if dimensions cannot be determined.
106
+ """
107
+
108
+ try:
109
+ root = ET.fromstring(data)
110
+ return _extract_dimensions_from_root(root)
111
+
112
+ except ET.XMLSyntaxError as ex:
113
+ LOGGER.warning("Failed to parse SVG data: %s", ex)
114
+ return None, None
115
+ except Exception as ex:
116
+ LOGGER.warning("Unexpected error reading SVG dimensions from data: %s", ex)
117
+ return None, None
118
+
119
+
120
+ def _serialize_svg_opening_tag(root: ElementType) -> str:
121
+ """
122
+ Serializes just the opening tag of an SVG element (without children or closing tag).
123
+
124
+ :param root: The root SVG element.
125
+ :returns: The opening tag string, e.g., '<svg width="100" height="200" ...>'.
126
+ """
127
+
128
+ # Build the opening tag from element name and attributes
129
+ root_tag = root.tag
130
+ if not isinstance(root_tag, str):
131
+ raise TypeError("expected: tag names as `str`")
132
+ tag_name = ET.QName(root_tag).localname
133
+ parts = [f"<{tag_name}"]
134
+
135
+ # Add namespace declarations (nsmap)
136
+ for prefix, uri in root.nsmap.items():
137
+ if prefix is None:
138
+ parts.append(f' xmlns="{uri}"')
139
+ else:
140
+ parts.append(f' xmlns:{prefix}="{uri}"')
141
+
142
+ # Add attributes
143
+ for name, value in root.attrib.items():
144
+ qname = ET.QName(name)
145
+
146
+ # Handle namespaced attributes
147
+ if qname.namespace:
148
+ # Find prefix for this namespace
149
+ prefix = None
150
+ for p, u in root.nsmap.items():
151
+ if u == qname.namespace and p is not None:
152
+ prefix = p
153
+ break
154
+ if prefix:
155
+ parts.append(f' {prefix}:{qname.localname}="{value}"')
156
+ else:
157
+ parts.append(f' {qname.localname}="{value}"')
158
+ else:
159
+ parts.append(f' {name}="{value}"')
160
+
161
+ parts.append(">")
162
+ return "".join(parts)
163
+
164
+
165
+ def fix_svg_dimensions(data: bytes) -> bytes:
166
+ """
167
+ Fixes SVG data by setting explicit width/height attributes based on viewBox.
168
+
169
+ Mermaid generates SVGs with width="100%" which Confluence doesn't handle well.
170
+ This function replaces percentage-based dimensions with explicit pixel values
171
+ derived from the viewBox.
172
+
173
+ Note: SVGs containing foreignObject elements are NOT modified, as Confluence
174
+ has rendering issues with foreignObject when explicit dimensions are set.
175
+
176
+ Uses lxml to parse and modify the root element's attributes, then replaces
177
+ just the opening tag in the original document to preserve the rest exactly.
178
+
179
+ :param data: The SVG content as bytes.
180
+ :returns: The modified SVG content with explicit dimensions, or original data if modification fails.
181
+ """
182
+
183
+ try:
184
+ text = data.decode("utf-8")
185
+
186
+ # Skip SVGs with foreignObject - Confluence has issues rendering
187
+ # foreignObject content when explicit width/height are set on the SVG
188
+ if "<foreignObject" in text:
189
+ LOGGER.debug("Skipping dimension fix for SVG with foreignObject elements")
190
+ return data
191
+
192
+ # Parse the SVG to extract root element attributes
193
+ root = ET.fromstring(data)
194
+
195
+ # Verify it's an SVG element
196
+ if not _check_svg(root):
197
+ return data
198
+
199
+ # Check if we need to fix (has width="100%" or similar percentage)
200
+ width_attr = root.get("width")
201
+ if width_attr != "100%":
202
+ # Check if it already has a valid numeric width
203
+ if width_attr is not None and _parse_svg_length(width_attr) is not None:
204
+ return data # Already has numeric width
205
+
206
+ # Get viewBox dimensions
207
+ viewbox = root.get("viewBox")
208
+ if not viewbox:
209
+ return data
210
+
211
+ vb_width, vb_height = _parse_viewbox(viewbox)
212
+ if vb_width is None or vb_height is None:
213
+ return data
214
+
215
+ # Extract the original opening tag from the text
216
+ svg_tag_match = re.search(r"<svg\b[^>]*>", text)
217
+ if not svg_tag_match:
218
+ return data
219
+
220
+ original_tag = svg_tag_match.group(0)
221
+
222
+ # Modify the root element's attributes
223
+ root.set("width", str(vb_width))
224
+
225
+ # Set height if missing or if it's a percentage
226
+ height_attr = root.get("height")
227
+ if height_attr is None or height_attr == "100%":
228
+ root.set("height", str(vb_height))
229
+
230
+ # Serialize just the opening tag with modified attributes
231
+ new_tag = _serialize_svg_opening_tag(root)
232
+
233
+ # Replace the original opening tag with the new one
234
+ text = text.replace(original_tag, new_tag, 1)
235
+
236
+ return text.encode("utf-8")
237
+
238
+ except Exception as ex:
239
+ LOGGER.warning("Unexpected error fixing SVG dimensions: %s", ex)
240
+ return data
241
+
242
+
243
+ def _parse_svg_length(value: str) -> int | None:
244
+ """
245
+ Parses an SVG length value and converts it to pixels.
246
+
247
+ Supports: px, pt, em, ex, in, cm, mm, pc, and unit-less values.
248
+ For simplicity, assumes 96 DPI and 16px base font size.
249
+
250
+ :param value: The SVG length string (e.g., "100", "100px", "10em").
251
+ :returns: The length in pixels as an integer, or None if parsing fails.
252
+ """
253
+
254
+ if not value:
255
+ return None
256
+
257
+ value = value.strip()
258
+
259
+ # Match number with optional unit
260
+ match = re.match(r"^([+-]?(?:\d+\.?\d*|\.\d+))(%|px|pt|em|ex|in|cm|mm|pc)?$", value, re.IGNORECASE)
261
+ if not match:
262
+ return None
263
+
264
+ num_str, unit = match.groups()
265
+ try:
266
+ num = float(num_str)
267
+ except ValueError:
268
+ return None
269
+
270
+ # Convert to pixels (assuming 96 DPI, 16px base font)
271
+ match unit.lower() if unit else None:
272
+ case None | "px":
273
+ pixels = num
274
+ case "pt":
275
+ pixels = num * 96 / 72 # 1pt = 1/72 inch
276
+ case "in":
277
+ pixels = num * 96
278
+ case "cm":
279
+ pixels = num * 96 / 2.54
280
+ case "mm":
281
+ pixels = num * 96 / 25.4
282
+ case "pc":
283
+ pixels = num * 96 / 6 # 1pc = 12pt = 1/6 inch
284
+ case "em":
285
+ pixels = num * 16 # assume 16px base font
286
+ case "ex":
287
+ pixels = num * 8 # assume ex ≈ 0.5em
288
+ case "%":
289
+ # Percentage values can't be resolved without a container; skip
290
+ return None
291
+ case _:
292
+ return None
293
+
294
+ return int(round(pixels))
295
+
296
+
297
+ def _parse_viewbox(viewbox: str) -> tuple[int | None, int | None]:
298
+ """
299
+ Parses an SVG viewBox attribute and extracts width and height.
300
+
301
+ :param viewbox: The viewBox string (e.g., "0 0 100 200").
302
+ :returns: A tuple of (width, height) in pixels, or (None, None) if parsing fails.
303
+ """
304
+
305
+ if not viewbox:
306
+ return None, None
307
+
308
+ # viewBox format: "min-x min-y width height"
309
+ # Values can be separated by whitespace and/or commas
310
+ parts = re.split(r"[\s,]+", viewbox.strip())
311
+ if len(parts) != 4:
312
+ return None, None
313
+
314
+ try:
315
+ width = int(round(float(parts[2])))
316
+ height = int(round(float(parts[3])))
317
+ return width, height
318
+ except ValueError:
319
+ return None, None
320
+
321
+
322
+ def fix_svg_get_dimensions(image_data: bytes) -> tuple[bytes, int | None, int | None]:
323
+ """
324
+ Post-processes SVG diagram data by fixing dimensions and extracting metadata.
325
+
326
+ This handles the common pattern for SVG diagrams:
327
+
328
+ 1. fixes SVG dimensions (converts percentage-based to explicit pixels), and
329
+ 2. extracts width/height from the SVG.
330
+
331
+ :param image_data: Raw SVG data as bytes.
332
+ :returns: Tuple of update raw data, image width, image height.
333
+ """
334
+
335
+ # fix SVG to have explicit width/height instead of percentages
336
+ image_data = fix_svg_dimensions(image_data)
337
+
338
+ # extract dimensions from the fixed SVG
339
+ width, height = get_svg_dimensions_from_bytes(image_data)
340
+
341
+ return image_data, width, height
md2conf/text.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """
2
2
  Publish Markdown files to Confluence wiki.
3
3
 
4
- Copyright 2022-2025, Levente Hunyadi
4
+ Copyright 2022-2026, Levente Hunyadi
5
5
 
6
6
  :see: https://github.com/hunyadi/md2conf
7
7
  """
md2conf/toc.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """
2
2
  Publish Markdown files to Confluence wiki.
3
3
 
4
- Copyright 2022-2025, Levente Hunyadi
4
+ Copyright 2022-2026, Levente Hunyadi
5
5
 
6
6
  :see: https://github.com/hunyadi/md2conf
7
7
  """
md2conf/uri.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """
2
2
  Publish Markdown files to Confluence wiki.
3
3
 
4
- Copyright 2022-2025, Levente Hunyadi
4
+ Copyright 2022-2026, Levente Hunyadi
5
5
 
6
6
  :see: https://github.com/hunyadi/md2conf
7
7
  """
md2conf/xml.py CHANGED
@@ -1,7 +1,7 @@
1
1
  """
2
2
  Publish Markdown files to Confluence wiki.
3
3
 
4
- Copyright 2022-2025, Levente Hunyadi
4
+ Copyright 2022-2026, Levente Hunyadi
5
5
 
6
6
  :see: https://github.com/hunyadi/md2conf
7
7
  """
@@ -1,35 +0,0 @@
1
- markdown_to_confluence-0.5.1.dist-info/licenses/LICENSE,sha256=56L-Y0dyZwyVlINRJRz3PNw-ka-oLVaAq-7d8zo6qlc,1077
2
- md2conf/__init__.py,sha256=BhdWezYDER-ShxuHElVX_sLnP_NkQ7WoO5tr318SwgE,402
3
- md2conf/__main__.py,sha256=ZAwZ2YqKUxKiVx8CQsrnso9z2deP5Xn80kqqf2o3AbY,11472
4
- md2conf/api.py,sha256=yFDsE_5IpCXG4z24ZrxF8QjF07ep3HiBHqaWKcGKf1k,40731
5
- md2conf/collection.py,sha256=nghFS5kK4kPbpLE7IHi4rprJK-Mu4KXNxjHYM9Rc5SQ,824
6
- md2conf/converter.py,sha256=BM94de0CAQGXOTSve7_042y3VF_yu77NITX5FUUeJPQ,69446
7
- md2conf/csf.py,sha256=rugs3qC2aJQCJSTczeBw9WhqSZZtMq14LjwT0V1b6Hc,6476
8
- md2conf/domain.py,sha256=EsaAfUaT2qIrK91uRyxaPEY4kSq-nzhccErxVqHdooc,2205
9
- md2conf/drawio.py,sha256=IqFlAegrKM5SQf5CqHD8STIzskH7Rpm9RtWwn_nXVTc,8581
10
- md2conf/emoticon.py,sha256=P2L5oQvnRXeVifJQ3sJ2Ck-6ptbxumq2vsT-rM0W0Ms,484
11
- md2conf/entities.dtd,sha256=M6NzqL5N7dPs_eUA_6sDsiSLzDaAacrx9LdttiufvYU,30215
12
- md2conf/environment.py,sha256=BhI7YktY7G26HOhGlUvTkH2Vmfa4E_dhu2snzbBgMvE,3902
13
- md2conf/extra.py,sha256=VuMxuOnnC2Qwy6y52ukIxsaYhrZArRqMmRHRE4QZl8g,687
14
- md2conf/latex.py,sha256=3eFgsvaq6ROAc2skW1Wq21CX_pJai1Yc9t861Z3s5XA,7600
15
- md2conf/local.py,sha256=Ou-j7kZWbHxC8Si8Yg7myqtTQ1He6mYQW1NpX3LLIcY,3704
16
- md2conf/markdown.py,sha256=t-z19Zs_91_jzRvwmOsWqCDt0Tdghmk5bpNUON0YlKc,3148
17
- md2conf/matcher.py,sha256=hkM49osFM9nrXRXe4pwcGCg0rrLsmKep7AYY_S01kNY,6774
18
- md2conf/mermaid.py,sha256=9P4VV69dooaFBNUjdTIpzq7BFA8rDMqEif1O7XKWPdM,2617
19
- md2conf/metadata.py,sha256=_kt_lh4gCzVRRhhrDk-cJCk9WMcX9ZDWB6hL0Lw3xoI,976
20
- md2conf/processor.py,sha256=8Y-NSxAuqSHMSN9vhw_83HisGAmq87XAY98dis_xZ0Y,9690
21
- md2conf/publisher.py,sha256=yI7gObPZLrNEXbiPKBJwkBPcGLI17UwzKd8FQe3U8bE,8634
22
- md2conf/puppeteer-config.json,sha256=-dMTAN_7kNTGbDlfXzApl0KJpAWna9YKZdwMKbpOb60,159
23
- md2conf/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
- md2conf/scanner.py,sha256=o46fTQXuTpbtvpnQPW3CW4ydIb5bM362K2TFpwO51P0,6782
25
- md2conf/serializer.py,sha256=JrBj8Z9zP8PjBeVAlRRqnMKDoz6IvkRbTd6K-JgFVow,1757
26
- md2conf/text.py,sha256=fHOrUaPXAjE4iRhHqFq-CiI-knpo4wvyHCWp0crewqA,1736
27
- md2conf/toc.py,sha256=ZrfUfTv_Jiv27G4SBNjK3b-1ClYKoqN5yPRsEWp6IXk,2413
28
- md2conf/uri.py,sha256=KbLBdRFtZTQTZd8b4j0LtE8Pb68Ly0WkemF4iW-EAB4,1158
29
- md2conf/xml.py,sha256=Fu00Eg8c0VgMHIjRDBJBSNWtui8obEtowkiR7gHTduM,5526
30
- markdown_to_confluence-0.5.1.dist-info/METADATA,sha256=Qttp8PjzAJnE6mJ_2-1ABYAVMCjEQeuL7QlaOcTmiEY,36463
31
- markdown_to_confluence-0.5.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
32
- markdown_to_confluence-0.5.1.dist-info/entry_points.txt,sha256=F1zxa1wtEObtbHS-qp46330WVFLHdMnV2wQ-ZorRmX0,50
33
- markdown_to_confluence-0.5.1.dist-info/top_level.txt,sha256=_FJfl_kHrHNidyjUOuS01ngu_jDsfc-ZjSocNRJnTzU,8
34
- markdown_to_confluence-0.5.1.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
35
- markdown_to_confluence-0.5.1.dist-info/RECORD,,
md2conf/domain.py DELETED
@@ -1,52 +0,0 @@
1
- """
2
- Publish Markdown files to Confluence wiki.
3
-
4
- Copyright 2022-2025, Levente Hunyadi
5
-
6
- :see: https://github.com/hunyadi/md2conf
7
- """
8
-
9
- from dataclasses import dataclass
10
- from typing import Literal
11
-
12
-
13
- @dataclass
14
- class ConfluencePageID:
15
- page_id: str
16
-
17
-
18
- @dataclass
19
- class ConfluenceDocumentOptions:
20
- """
21
- Options that control the generated page content.
22
-
23
- :param ignore_invalid_url: When true, ignore invalid URLs in input, emit a warning and replace the anchor with
24
- plain text; when false, raise an exception.
25
- :param heading_anchors: When true, emit a structured macro *anchor* for each section heading using GitHub
26
- conversion rules for the identifier.
27
- :param generated_by: Text to use as the generated-by prompt (or `None` to omit a prompt).
28
- :param root_page_id: Confluence page to assume root page role for publishing a directory of Markdown files.
29
- :param keep_hierarchy: Whether to maintain source directory structure when exporting to Confluence.
30
- :param prefer_raster: Whether to choose PNG files over SVG files when available.
31
- :param render_drawio: Whether to pre-render (or use the pre-rendered version of) draw.io diagrams.
32
- :param render_mermaid: Whether to pre-render Mermaid diagrams into PNG/SVG images.
33
- :param render_latex: Whether to pre-render LaTeX formulas into PNG/SVG images.
34
- :param diagram_output_format: Target image format for diagrams.
35
- :param webui_links: When true, convert relative URLs to Confluence Web UI links.
36
- :param alignment: Alignment for block-level images and formulas.
37
- :param use_panel: Whether to transform admonitions and alerts into a Confluence custom panel.
38
- """
39
-
40
- ignore_invalid_url: bool = False
41
- heading_anchors: bool = False
42
- generated_by: str | None = "This page has been generated with a tool."
43
- root_page_id: ConfluencePageID | None = None
44
- keep_hierarchy: bool = False
45
- prefer_raster: bool = True
46
- render_drawio: bool = False
47
- render_mermaid: bool = False
48
- render_latex: bool = False
49
- diagram_output_format: Literal["png", "svg"] = "png"
50
- webui_links: bool = False
51
- alignment: Literal["center", "left", "right"] = "center"
52
- use_panel: bool = False