mkdocs2confluence 0.17.0__tar.gz → 0.17.2__tar.gz

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 (112) hide show
  1. {mkdocs2confluence-0.17.0/src/mkdocs2confluence.egg-info → mkdocs2confluence-0.17.2}/PKG-INFO +1 -1
  2. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/pyproject.toml +1 -1
  3. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2/src/mkdocs2confluence.egg-info}/PKG-INFO +1 -1
  4. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/parser/markdown.py +3 -2
  5. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/plantuml.py +24 -14
  6. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_mermaid.py +7 -0
  7. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_plantuml.py +25 -18
  8. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/LICENSE +0 -0
  9. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/README.md +0 -0
  10. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/setup.cfg +0 -0
  11. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs2confluence.egg-info/SOURCES.txt +0 -0
  12. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs2confluence.egg-info/dependency_links.txt +0 -0
  13. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs2confluence.egg-info/entry_points.txt +0 -0
  14. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs2confluence.egg-info/requires.txt +0 -0
  15. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs2confluence.egg-info/top_level.txt +0 -0
  16. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/__init__.py +0 -0
  17. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/cli.py +0 -0
  18. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/compiler/__init__.py +0 -0
  19. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/compiler/models.py +0 -0
  20. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/compiler/page.py +0 -0
  21. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/emitter/__init__.py +0 -0
  22. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/emitter/xhtml.py +0 -0
  23. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/ir/__init__.py +0 -0
  24. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/ir/document.py +0 -0
  25. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/ir/nodes.py +0 -0
  26. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/ir/treeutil.py +0 -0
  27. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/loader/__init__.py +0 -0
  28. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/loader/config.py +0 -0
  29. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/loader/extra_css.py +0 -0
  30. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/loader/nav.py +0 -0
  31. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/loader/page.py +0 -0
  32. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/parser/__init__.py +0 -0
  33. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/pdf/__init__.py +0 -0
  34. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/pdf/generator.py +0 -0
  35. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/pdf/render.py +0 -0
  36. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preprocess/__init__.py +0 -0
  37. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preprocess/abbrevs.py +0 -0
  38. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preprocess/captions.py +0 -0
  39. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preprocess/fence.py +0 -0
  40. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preprocess/frontmatter.py +0 -0
  41. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preprocess/icons.py +0 -0
  42. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preprocess/includes.py +0 -0
  43. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preprocess/linkdefs.py +0 -0
  44. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preview/__init__.py +0 -0
  45. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preview/render.py +0 -0
  46. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preview/server.py +0 -0
  47. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/publisher/__init__.py +0 -0
  48. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/publisher/changelog.py +0 -0
  49. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/publisher/client.py +0 -0
  50. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/publisher/executor.py +0 -0
  51. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/publisher/http_retry.py +0 -0
  52. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/publisher/models.py +0 -0
  53. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/publisher/pipeline.py +0 -0
  54. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/publisher/planner.py +0 -0
  55. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/skill_installer.py +0 -0
  56. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/skills/mkdocs-changelog/SKILL.md +0 -0
  57. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/skills/mkdocs-changelog/scripts/changelog_data.py +0 -0
  58. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/sync/__init__.py +0 -0
  59. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/sync/anchoring.py +0 -0
  60. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/sync/command.py +0 -0
  61. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/sync/comments.py +0 -0
  62. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/sync/github.py +0 -0
  63. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/sync/platform.py +0 -0
  64. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/sync/state.py +0 -0
  65. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/__init__.py +0 -0
  66. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/_kroki.py +0 -0
  67. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/abbrevs.py +0 -0
  68. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/admonition_titles.py +0 -0
  69. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/assets.py +0 -0
  70. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/attachment_previews.py +0 -0
  71. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/captions.py +0 -0
  72. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/editlink.py +0 -0
  73. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/footer.py +0 -0
  74. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/images.py +0 -0
  75. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/internallinks.py +0 -0
  76. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/mermaid.py +0 -0
  77. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_abbrevs.py +0 -0
  78. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_admonition_titles.py +0 -0
  79. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_attachment_previews.py +0 -0
  80. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_captions.py +0 -0
  81. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_changelog_config.py +0 -0
  82. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_changelog_publish.py +0 -0
  83. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_children_macro.py +0 -0
  84. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_cli.py +0 -0
  85. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_editlink.py +0 -0
  86. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_emitter.py +0 -0
  87. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_exclude_properties_config.py +0 -0
  88. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_extra_css.py +0 -0
  89. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_footer.py +0 -0
  90. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_frontmatter.py +0 -0
  91. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_icons.py +0 -0
  92. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_images.py +0 -0
  93. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_internallinks.py +0 -0
  94. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_ir.py +0 -0
  95. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_linkdefs.py +0 -0
  96. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_loader.py +0 -0
  97. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_page_loader.py +0 -0
  98. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_parser.py +0 -0
  99. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_pdf.py +0 -0
  100. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_preprocess.py +0 -0
  101. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_preview.py +0 -0
  102. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_publish_client.py +0 -0
  103. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_publish_config.py +0 -0
  104. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_publish_pipeline.py +0 -0
  105. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_server.py +0 -0
  106. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_skill_installer.py +0 -0
  107. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_sync_anchoring.py +0 -0
  108. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_sync_command.py +0 -0
  109. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_sync_comments.py +0 -0
  110. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_sync_github.py +0 -0
  111. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_sync_state.py +0 -0
  112. {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_treeutil.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mkdocs2confluence
3
- Version: 0.17.0
3
+ Version: 0.17.2
4
4
  Summary: Publish MkDocs Material pages to Confluence Cloud — admonitions, Mermaid diagrams, tabs, page properties and more
5
5
  Author: Anders Hybertz
6
6
  License: GPL-3.0-or-later
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mkdocs2confluence"
3
- version = "0.17.0"
3
+ version = "0.17.2"
4
4
  description = "Publish MkDocs Material pages to Confluence Cloud — admonitions, Mermaid diagrams, tabs, page properties and more"
5
5
  readme = "README.md"
6
6
  license = { text = "GPL-3.0-or-later" }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mkdocs2confluence
3
- Version: 0.17.0
3
+ Version: 0.17.2
4
4
  Summary: Publish MkDocs Material pages to Confluence Cloud — admonitions, Mermaid diagrams, tabs, page properties and more
5
5
  Author: Anders Hybertz
6
6
  License: GPL-3.0-or-later
@@ -1140,9 +1140,10 @@ def _build_tree(
1140
1140
  _append_content(node, stack, root)
1141
1141
 
1142
1142
  elif isinstance(token, _CodeToken):
1143
- if token.language and token.language.lower() == "mermaid":
1143
+ lang = token.language.lower() if token.language else ""
1144
+ if lang in ("mermaid", "kroki-mermaid"):
1144
1145
  _append_content(MermaidDiagram(source=token.code), stack, root)
1145
- elif token.language and token.language.lower() == "plantuml":
1146
+ elif lang in ("plantuml", "kroki-plantuml"):
1146
1147
  _append_content(PlantUMLDiagram(source=token.code), stack, root)
1147
1148
  else:
1148
1149
  _append_content(
@@ -1,8 +1,13 @@
1
1
  """PlantUML diagram rendering transform.
2
2
 
3
- Walks the IR tree, finds :class:`PlantUMLDiagram` nodes, renders each to PNG
3
+ Walks the IR tree, finds :class:`PlantUMLDiagram` nodes, renders each to SVG
4
4
  via the Kroki rendering service, caches results locally, and returns updated
5
- nodes with ``attachment_name`` set plus a list of PNG paths to upload.
5
+ nodes with ``attachment_name`` set plus a list of SVG paths to upload.
6
+
7
+ SVG (vector) output is used rather than PNG because PlantUML caps raster output
8
+ at ``PLANTUML_LIMIT_SIZE`` pixels (default 4096) per dimension, which causes
9
+ large diagrams to fail rendering. SVG is not subject to that limit, scales
10
+ crisply, and is supported by Confluence attachments.
6
11
 
7
12
  The cache lives at ``~/.cache/mk2conf/plantuml/`` and is keyed by the SHA-256
8
13
  of the PlantUML source so unchanged diagrams are never re-fetched.
@@ -25,7 +30,6 @@ from typing import cast
25
30
  from mkdocs_to_confluence.ir.nodes import IRNode, PlantUMLDiagram
26
31
  from mkdocs_to_confluence.transforms._kroki import (
27
32
  _CACHE_LOCK,
28
- _MIN_PNG_BYTES,
29
33
  _RETRY_ATTEMPTS,
30
34
  _RETRY_BACKOFF,
31
35
  _RETRYABLE_HTTP,
@@ -37,16 +41,16 @@ from mkdocs_to_confluence.transforms._kroki import (
37
41
  _CACHE_DIR = Path.home() / ".cache" / "mk2conf" / "plantuml"
38
42
 
39
43
 
40
- def _kroki_png(source: str, kroki_url: str) -> bytes:
41
- """Fetch a PNG rendering of *source* from the Kroki service (POST)."""
42
- url = f"{kroki_url.rstrip('/')}/plantuml/png"
44
+ def _kroki_svg(source: str, kroki_url: str) -> bytes:
45
+ """Fetch an SVG rendering of *source* from the Kroki service (POST)."""
46
+ url = f"{kroki_url.rstrip('/')}/plantuml/svg"
43
47
  body = source.encode("utf-8")
44
48
  req = urllib.request.Request(
45
49
  url,
46
50
  data=body,
47
51
  headers={
48
52
  "Content-Type": "text/plain",
49
- "Accept": "image/png",
53
+ "Accept": "image/svg+xml",
50
54
  "User-Agent": "mk2conf/1.0",
51
55
  },
52
56
  method="POST",
@@ -55,9 +59,15 @@ def _kroki_png(source: str, kroki_url: str) -> bytes:
55
59
  return cast(bytes, resp.read())
56
60
 
57
61
 
62
+ def _looks_like_svg(data: bytes) -> bool:
63
+ """Heuristic: does *data* look like a valid SVG document?"""
64
+ head = data[:512].lstrip()
65
+ return head.startswith(b"<?xml") or head.startswith(b"<svg") or b"<svg" in head
66
+
67
+
58
68
  def _cache_path(source: str) -> Path:
59
69
  digest = hashlib.sha256(source.encode()).hexdigest()
60
- return _CACHE_DIR / f"plantuml_{digest}.png"
70
+ return _CACHE_DIR / f"plantuml_{digest}.svg"
61
71
 
62
72
 
63
73
  def _warn(msg: str) -> None:
@@ -87,11 +97,11 @@ def _render_one(source: str, kroki_url: str, *, quiet: bool = False) -> Path | N
87
97
  try:
88
98
  if not quiet:
89
99
  print(f" rendering plantuml diagram via Kroki ({kroki_url})")
90
- png = _kroki_png(source, kroki_url)
91
- if len(png) < _MIN_PNG_BYTES:
92
- raise ValueError(f"Kroki returned {len(png)} bytes (expected a valid PNG)")
100
+ svg = _kroki_svg(source, kroki_url)
101
+ if not _looks_like_svg(svg):
102
+ raise ValueError(f"Kroki returned {len(svg)} bytes (expected a valid SVG)")
93
103
  with _CACHE_LOCK:
94
- path.write_bytes(png)
104
+ path.write_bytes(svg)
95
105
  return path
96
106
  except urllib.error.HTTPError as exc:
97
107
  if exc.code in _RETRYABLE_HTTP:
@@ -116,11 +126,11 @@ def render_plantuml_diagrams(
116
126
  *,
117
127
  quiet: bool = False,
118
128
  ) -> tuple[tuple[IRNode, ...], list[Path]]:
119
- """Render all :class:`PlantUMLDiagram` nodes to PNG via Kroki.
129
+ """Render all :class:`PlantUMLDiagram` nodes to SVG via Kroki.
120
130
 
121
131
  Diagrams are rendered concurrently (up to ``_MAX_WORKERS`` threads).
122
132
  Returns the updated IR node tuple (with ``attachment_name`` set on each
123
- successfully rendered diagram) and a list of PNG :class:`Path` objects to
133
+ successfully rendered diagram) and a list of SVG :class:`Path` objects to
124
134
  upload as page attachments.
125
135
 
126
136
  Diagrams that fail to render are left unchanged (code-block fallback).
@@ -26,6 +26,13 @@ def test_parser_produces_mermaid_diagram_node():
26
26
  assert "graph TD" in nodes[0].source
27
27
 
28
28
 
29
+ def test_parser_kroki_mermaid_alias():
30
+ """A ```kroki-mermaid fenced block must also parse to MermaidDiagram."""
31
+ nodes = parse("```kroki-mermaid\ngraph TD\n A --> B\n```\n")
32
+ assert len(nodes) == 1
33
+ assert isinstance(nodes[0], MermaidDiagram)
34
+
35
+
29
36
  def test_parser_non_mermaid_code_block_stays_codeblock():
30
37
  """A ```python block must still parse to CodeBlock."""
31
38
  nodes = parse("```python\nprint('hello')\n```\n")
@@ -12,7 +12,7 @@ from mkdocs_to_confluence.transforms.plantuml import (
12
12
  )
13
13
 
14
14
  _SAMPLE_SOURCE = "@startuml\nAlice -> Bob: Hello\n@enduml\n"
15
- _FAKE_PNG = b"\x89PNG\r\n\x1a\n" + b"\x00" * 100 # fake PNG > _MIN_PNG_BYTES (67)
15
+ _FAKE_SVG = b'<?xml version="1.0"?><svg xmlns="http://www.w3.org/2000/svg"></svg>'
16
16
 
17
17
 
18
18
  # ── Parser ────────────────────────────────────────────────────────────────────
@@ -33,6 +33,13 @@ def test_parser_plantuml_case_insensitive():
33
33
  assert isinstance(nodes[0], PlantUMLDiagram)
34
34
 
35
35
 
36
+ def test_parser_kroki_plantuml_alias():
37
+ """A ```kroki-plantuml fenced block must also parse to PlantUMLDiagram."""
38
+ nodes = parse("```kroki-plantuml\n@startuml\nA -> B\n@enduml\n```\n")
39
+ assert len(nodes) == 1
40
+ assert isinstance(nodes[0], PlantUMLDiagram)
41
+
42
+
36
43
  def test_parser_non_plantuml_code_block_stays_codeblock():
37
44
  """A ```python block must still parse to CodeBlock."""
38
45
  nodes = parse("```python\nprint('hello')\n```\n")
@@ -53,10 +60,10 @@ def test_emit_plantuml_fallback_code_block():
53
60
 
54
61
  def test_emit_plantuml_attachment_image():
55
62
  """With attachment_name set the emitter produces an ac:image."""
56
- node = PlantUMLDiagram(source=_SAMPLE_SOURCE, attachment_name="plantuml_abc123.png")
63
+ node = PlantUMLDiagram(source=_SAMPLE_SOURCE, attachment_name="plantuml_abc123.svg")
57
64
  result = emit((node,))
58
65
  assert '<ac:image ac:align="center">' in result
59
- assert 'ri:filename="plantuml_abc123.png"' in result
66
+ assert 'ri:filename="plantuml_abc123.svg"' in result
60
67
  assert "code" not in result
61
68
 
62
69
 
@@ -69,7 +76,7 @@ def test_render_uses_cache_on_second_call(tmp_path):
69
76
 
70
77
  with (
71
78
  patch("mkdocs_to_confluence.transforms.plantuml._CACHE_DIR", tmp_path),
72
- patch("mkdocs_to_confluence.transforms.plantuml._kroki_png", return_value=_FAKE_PNG) as mock_fetch,
79
+ patch("mkdocs_to_confluence.transforms.plantuml._kroki_svg", return_value=_FAKE_SVG) as mock_fetch,
73
80
  ):
74
81
  render_plantuml_diagrams((node,))
75
82
  render_plantuml_diagrams((node,))
@@ -82,12 +89,12 @@ def test_render_sets_attachment_name(tmp_path):
82
89
 
83
90
  with (
84
91
  patch("mkdocs_to_confluence.transforms.plantuml._CACHE_DIR", tmp_path),
85
- patch("mkdocs_to_confluence.transforms.plantuml._kroki_png", return_value=_FAKE_PNG),
92
+ patch("mkdocs_to_confluence.transforms.plantuml._kroki_svg", return_value=_FAKE_SVG),
86
93
  ):
87
94
  updated_nodes, attachments = render_plantuml_diagrams((node,))
88
95
 
89
96
  assert len(attachments) == 1
90
- assert attachments[0].suffix == ".png"
97
+ assert attachments[0].suffix == ".svg"
91
98
  rendered = updated_nodes[0]
92
99
  assert isinstance(rendered, PlantUMLDiagram)
93
100
  assert rendered.attachment_name == attachments[0].name
@@ -100,7 +107,7 @@ def test_render_deduplicates_identical_diagrams(tmp_path):
100
107
 
101
108
  with (
102
109
  patch("mkdocs_to_confluence.transforms.plantuml._CACHE_DIR", tmp_path),
103
- patch("mkdocs_to_confluence.transforms.plantuml._kroki_png", return_value=_FAKE_PNG),
110
+ patch("mkdocs_to_confluence.transforms.plantuml._kroki_svg", return_value=_FAKE_SVG),
104
111
  ):
105
112
  _, attachments = render_plantuml_diagrams((node_a, node_b))
106
113
 
@@ -117,7 +124,7 @@ def test_render_fallback_on_network_error(tmp_path, capsys):
117
124
  patch("mkdocs_to_confluence.transforms.plantuml._CACHE_DIR", tmp_path),
118
125
  patch("mkdocs_to_confluence.transforms.plantuml.time.sleep"),
119
126
  patch(
120
- "mkdocs_to_confluence.transforms.plantuml._kroki_png",
127
+ "mkdocs_to_confluence.transforms.plantuml._kroki_svg",
121
128
  side_effect=urllib.error.URLError("timed out"),
122
129
  ),
123
130
  ):
@@ -139,7 +146,7 @@ def test_render_fallback_on_http_error(tmp_path, capsys):
139
146
  patch("mkdocs_to_confluence.transforms.plantuml._CACHE_DIR", tmp_path),
140
147
  patch("mkdocs_to_confluence.transforms.plantuml.time.sleep"),
141
148
  patch(
142
- "mkdocs_to_confluence.transforms.plantuml._kroki_png",
149
+ "mkdocs_to_confluence.transforms.plantuml._kroki_svg",
143
150
  side_effect=urllib.error.HTTPError(
144
151
  url=None, code=503, msg="Service Unavailable", hdrs=None, fp=None # type: ignore[arg-type]
145
152
  ),
@@ -160,7 +167,7 @@ def test_render_fallback_on_empty_response(tmp_path, capsys):
160
167
  with (
161
168
  patch("mkdocs_to_confluence.transforms.plantuml._CACHE_DIR", tmp_path),
162
169
  patch(
163
- "mkdocs_to_confluence.transforms.plantuml._kroki_png",
170
+ "mkdocs_to_confluence.transforms.plantuml._kroki_svg",
164
171
  return_value=b"",
165
172
  ),
166
173
  ):
@@ -179,11 +186,11 @@ def test_render_uses_custom_kroki_url(tmp_path):
179
186
 
180
187
  def fake_fetch(source: str, kroki_url: str) -> bytes:
181
188
  captured.append(kroki_url)
182
- return _FAKE_PNG
189
+ return _FAKE_SVG
183
190
 
184
191
  with (
185
192
  patch("mkdocs_to_confluence.transforms.plantuml._CACHE_DIR", tmp_path),
186
- patch("mkdocs_to_confluence.transforms.plantuml._kroki_png", side_effect=fake_fetch),
193
+ patch("mkdocs_to_confluence.transforms.plantuml._kroki_svg", side_effect=fake_fetch),
187
194
  ):
188
195
  render_plantuml_diagrams((node,), kroki_url="https://internal.kroki")
189
196
 
@@ -194,7 +201,7 @@ def test_render_plantuml_none_skips(tmp_path):
194
201
  """Nodes with attachment_name already set are left untouched."""
195
202
  node = PlantUMLDiagram(source=_SAMPLE_SOURCE, attachment_name="already_set.png")
196
203
 
197
- with patch("mkdocs_to_confluence.transforms.plantuml._kroki_png") as mock_fetch:
204
+ with patch("mkdocs_to_confluence.transforms.plantuml._kroki_svg") as mock_fetch:
198
205
  updated_nodes, attachments = render_plantuml_diagrams((node,))
199
206
 
200
207
  mock_fetch.assert_not_called()
@@ -208,7 +215,7 @@ def test_render_multiple_diagrams_concurrently(tmp_path):
208
215
  nodes = tuple(PlantUMLDiagram(source=s) for s in sources)
209
216
 
210
217
  with patch("mkdocs_to_confluence.transforms.plantuml._CACHE_DIR", tmp_path), \
211
- patch("mkdocs_to_confluence.transforms.plantuml._kroki_png", return_value=_FAKE_PNG):
218
+ patch("mkdocs_to_confluence.transforms.plantuml._kroki_svg", return_value=_FAKE_SVG):
212
219
  updated, attachments = render_plantuml_diagrams(nodes)
213
220
 
214
221
  assert len(attachments) == 4
@@ -223,7 +230,7 @@ def test_render_retries_on_503_then_succeeds(tmp_path):
223
230
 
224
231
  from mkdocs_to_confluence.transforms.plantuml import _render_one
225
232
 
226
- calls = [urllib.error.HTTPError("url", 503, "Service Unavailable", {}, None), _FAKE_PNG]
233
+ calls = [urllib.error.HTTPError("url", 503, "Service Unavailable", {}, None), _FAKE_SVG]
227
234
 
228
235
  def fake_kroki(source: str, url: str) -> bytes:
229
236
  result = calls.pop(0)
@@ -233,7 +240,7 @@ def test_render_retries_on_503_then_succeeds(tmp_path):
233
240
 
234
241
  with patch("mkdocs_to_confluence.transforms.plantuml._CACHE_DIR", tmp_path), \
235
242
  patch("mkdocs_to_confluence.transforms.plantuml.time.sleep") as mock_sleep, \
236
- patch("mkdocs_to_confluence.transforms.plantuml._kroki_png", side_effect=fake_kroki):
243
+ patch("mkdocs_to_confluence.transforms.plantuml._kroki_svg", side_effect=fake_kroki):
237
244
  result = _render_one(_SAMPLE_SOURCE, "https://kroki.io")
238
245
 
239
246
  assert result is not None
@@ -249,7 +256,7 @@ def test_render_no_mermaid_ink_fallback(tmp_path):
249
256
 
250
257
  with patch("mkdocs_to_confluence.transforms.plantuml._CACHE_DIR", tmp_path), \
251
258
  patch("mkdocs_to_confluence.transforms.plantuml.time.sleep"), \
252
- patch("mkdocs_to_confluence.transforms.plantuml._kroki_png",
259
+ patch("mkdocs_to_confluence.transforms.plantuml._kroki_svg",
253
260
  side_effect=urllib.error.HTTPError("url", 504, "Gateway Timeout", {}, None)):
254
261
  result = _render_one(_SAMPLE_SOURCE, "https://kroki.io")
255
262
 
@@ -262,7 +269,7 @@ def test_render_quiet_suppresses_stdout(tmp_path, capsys):
262
269
 
263
270
  with (
264
271
  patch("mkdocs_to_confluence.transforms.plantuml._CACHE_DIR", tmp_path),
265
- patch("mkdocs_to_confluence.transforms.plantuml._kroki_png", return_value=_FAKE_PNG),
272
+ patch("mkdocs_to_confluence.transforms.plantuml._kroki_svg", return_value=_FAKE_SVG),
266
273
  ):
267
274
  render_plantuml_diagrams((node,), quiet=True)
268
275