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.
- {mkdocs2confluence-0.17.0/src/mkdocs2confluence.egg-info → mkdocs2confluence-0.17.2}/PKG-INFO +1 -1
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/pyproject.toml +1 -1
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2/src/mkdocs2confluence.egg-info}/PKG-INFO +1 -1
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/parser/markdown.py +3 -2
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/plantuml.py +24 -14
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_mermaid.py +7 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_plantuml.py +25 -18
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/LICENSE +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/README.md +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/setup.cfg +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs2confluence.egg-info/SOURCES.txt +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs2confluence.egg-info/dependency_links.txt +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs2confluence.egg-info/entry_points.txt +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs2confluence.egg-info/requires.txt +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs2confluence.egg-info/top_level.txt +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/__init__.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/cli.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/compiler/__init__.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/compiler/models.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/compiler/page.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/emitter/__init__.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/emitter/xhtml.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/ir/__init__.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/ir/document.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/ir/nodes.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/ir/treeutil.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/loader/__init__.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/loader/config.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/loader/extra_css.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/loader/nav.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/loader/page.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/parser/__init__.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/pdf/__init__.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/pdf/generator.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/pdf/render.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preprocess/__init__.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preprocess/abbrevs.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preprocess/captions.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preprocess/fence.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preprocess/frontmatter.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preprocess/icons.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preprocess/includes.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preprocess/linkdefs.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preview/__init__.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preview/render.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preview/server.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/publisher/__init__.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/publisher/changelog.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/publisher/client.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/publisher/executor.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/publisher/http_retry.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/publisher/models.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/publisher/pipeline.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/publisher/planner.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/skill_installer.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/skills/mkdocs-changelog/SKILL.md +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/skills/mkdocs-changelog/scripts/changelog_data.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/sync/__init__.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/sync/anchoring.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/sync/command.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/sync/comments.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/sync/github.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/sync/platform.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/sync/state.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/__init__.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/_kroki.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/abbrevs.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/admonition_titles.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/assets.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/attachment_previews.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/captions.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/editlink.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/footer.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/images.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/internallinks.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/mermaid.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_abbrevs.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_admonition_titles.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_attachment_previews.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_captions.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_changelog_config.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_changelog_publish.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_children_macro.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_cli.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_editlink.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_emitter.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_exclude_properties_config.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_extra_css.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_footer.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_frontmatter.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_icons.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_images.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_internallinks.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_ir.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_linkdefs.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_loader.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_page_loader.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_parser.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_pdf.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_preprocess.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_preview.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_publish_client.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_publish_config.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_publish_pipeline.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_server.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_skill_installer.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_sync_anchoring.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_sync_command.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_sync_comments.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_sync_github.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_sync_state.py +0 -0
- {mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_treeutil.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "mkdocs2confluence"
|
|
3
|
-
version = "0.17.
|
|
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" }
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/parser/markdown.py
RENAMED
|
@@ -1140,9 +1140,10 @@ def _build_tree(
|
|
|
1140
1140
|
_append_content(node, stack, root)
|
|
1141
1141
|
|
|
1142
1142
|
elif isinstance(token, _CodeToken):
|
|
1143
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
41
|
-
"""Fetch
|
|
42
|
-
url = f"{kroki_url.rstrip('/')}/plantuml/
|
|
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/
|
|
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}.
|
|
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
|
-
|
|
91
|
-
if
|
|
92
|
-
raise ValueError(f"Kroki returned {len(
|
|
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(
|
|
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
|
|
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
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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 == ".
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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),
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs2confluence.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs2confluence.egg-info/requires.txt
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs2confluence.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/compiler/__init__.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/compiler/models.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/compiler/page.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/emitter/__init__.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/emitter/xhtml.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/ir/__init__.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/ir/document.py
RENAMED
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/ir/treeutil.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/loader/__init__.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/loader/config.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/loader/extra_css.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/loader/nav.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/loader/page.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/parser/__init__.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/pdf/__init__.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/pdf/generator.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/pdf/render.py
RENAMED
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preprocess/abbrevs.py
RENAMED
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preprocess/fence.py
RENAMED
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preprocess/icons.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preview/__init__.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preview/render.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/preview/server.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/publisher/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/publisher/client.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/publisher/executor.py
RENAMED
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/publisher/models.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/publisher/pipeline.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/publisher/planner.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/skill_installer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/sync/__init__.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/sync/anchoring.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/sync/command.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/sync/comments.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/sync/github.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/sync/platform.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/sync/state.py
RENAMED
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/_kroki.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/abbrevs.py
RENAMED
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/assets.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/footer.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/images.py
RENAMED
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/src/mkdocs_to_confluence/transforms/mermaid.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.17.0 → mkdocs2confluence-0.17.2}/tests/test_exclude_properties_config.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|