mkdocs2confluence 0.17.2__tar.gz → 0.17.4__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.2/src/mkdocs2confluence.egg-info → mkdocs2confluence-0.17.4}/PKG-INFO +4 -4
  2. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/pyproject.toml +6 -6
  3. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4/src/mkdocs2confluence.egg-info}/PKG-INFO +4 -4
  4. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs2confluence.egg-info/SOURCES.txt +0 -2
  5. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs2confluence.egg-info/requires.txt +3 -3
  6. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/cli.py +7 -6
  7. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/emitter/xhtml.py +9 -2
  8. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/ir/__init__.py +0 -6
  9. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/ir/nodes.py +1 -0
  10. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/publisher/changelog.py +16 -19
  11. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/publisher/executor.py +4 -4
  12. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/publisher/planner.py +15 -49
  13. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/transforms/_kroki.py +8 -5
  14. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/transforms/admonition_titles.py +1 -4
  15. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/transforms/assets.py +3 -3
  16. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/transforms/mermaid.py +5 -24
  17. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/transforms/plantuml.py +5 -27
  18. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_attachment_previews.py +3 -3
  19. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_captions.py +2 -2
  20. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_changelog_publish.py +16 -12
  21. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_children_macro.py +4 -4
  22. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_cli.py +5 -4
  23. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_emitter.py +18 -3
  24. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_images.py +4 -4
  25. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_ir.py +0 -109
  26. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_mermaid.py +26 -26
  27. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_plantuml.py +14 -14
  28. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_publish_pipeline.py +105 -86
  29. mkdocs2confluence-0.17.2/src/mkdocs_to_confluence/ir/document.py +0 -66
  30. mkdocs2confluence-0.17.2/src/mkdocs_to_confluence/publisher/pipeline.py +0 -46
  31. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/LICENSE +0 -0
  32. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/README.md +0 -0
  33. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/setup.cfg +0 -0
  34. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs2confluence.egg-info/dependency_links.txt +0 -0
  35. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs2confluence.egg-info/entry_points.txt +0 -0
  36. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs2confluence.egg-info/top_level.txt +0 -0
  37. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/__init__.py +0 -0
  38. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/compiler/__init__.py +0 -0
  39. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/compiler/models.py +0 -0
  40. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/compiler/page.py +0 -0
  41. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/emitter/__init__.py +0 -0
  42. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/ir/treeutil.py +0 -0
  43. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/loader/__init__.py +0 -0
  44. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/loader/config.py +0 -0
  45. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/loader/extra_css.py +0 -0
  46. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/loader/nav.py +0 -0
  47. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/loader/page.py +0 -0
  48. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/parser/__init__.py +0 -0
  49. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/parser/markdown.py +0 -0
  50. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/pdf/__init__.py +0 -0
  51. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/pdf/generator.py +0 -0
  52. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/pdf/render.py +0 -0
  53. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/preprocess/__init__.py +0 -0
  54. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/preprocess/abbrevs.py +0 -0
  55. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/preprocess/captions.py +0 -0
  56. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/preprocess/fence.py +0 -0
  57. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/preprocess/frontmatter.py +0 -0
  58. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/preprocess/icons.py +0 -0
  59. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/preprocess/includes.py +0 -0
  60. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/preprocess/linkdefs.py +0 -0
  61. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/preview/__init__.py +0 -0
  62. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/preview/render.py +0 -0
  63. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/preview/server.py +0 -0
  64. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/publisher/__init__.py +0 -0
  65. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/publisher/client.py +0 -0
  66. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/publisher/http_retry.py +0 -0
  67. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/publisher/models.py +0 -0
  68. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/skill_installer.py +0 -0
  69. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/skills/mkdocs-changelog/SKILL.md +0 -0
  70. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/skills/mkdocs-changelog/scripts/changelog_data.py +0 -0
  71. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/sync/__init__.py +0 -0
  72. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/sync/anchoring.py +0 -0
  73. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/sync/command.py +0 -0
  74. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/sync/comments.py +0 -0
  75. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/sync/github.py +0 -0
  76. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/sync/platform.py +0 -0
  77. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/sync/state.py +0 -0
  78. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/transforms/__init__.py +0 -0
  79. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/transforms/abbrevs.py +0 -0
  80. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/transforms/attachment_previews.py +0 -0
  81. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/transforms/captions.py +0 -0
  82. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/transforms/editlink.py +0 -0
  83. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/transforms/footer.py +0 -0
  84. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/transforms/images.py +0 -0
  85. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/src/mkdocs_to_confluence/transforms/internallinks.py +0 -0
  86. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_abbrevs.py +0 -0
  87. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_admonition_titles.py +0 -0
  88. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_changelog_config.py +0 -0
  89. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_editlink.py +0 -0
  90. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_exclude_properties_config.py +0 -0
  91. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_extra_css.py +0 -0
  92. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_footer.py +0 -0
  93. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_frontmatter.py +0 -0
  94. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_icons.py +0 -0
  95. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_internallinks.py +0 -0
  96. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_linkdefs.py +0 -0
  97. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_loader.py +0 -0
  98. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_page_loader.py +0 -0
  99. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_parser.py +0 -0
  100. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_pdf.py +0 -0
  101. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_preprocess.py +0 -0
  102. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_preview.py +0 -0
  103. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_publish_client.py +0 -0
  104. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_publish_config.py +0 -0
  105. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_server.py +0 -0
  106. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_skill_installer.py +0 -0
  107. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_sync_anchoring.py +0 -0
  108. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_sync_command.py +0 -0
  109. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_sync_comments.py +0 -0
  110. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_sync_github.py +0 -0
  111. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_sync_state.py +0 -0
  112. {mkdocs2confluence-0.17.2 → mkdocs2confluence-0.17.4}/tests/test_treeutil.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mkdocs2confluence
3
- Version: 0.17.2
3
+ Version: 0.17.4
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
@@ -24,11 +24,11 @@ Requires-Python: >=3.12
24
24
  Description-Content-Type: text/markdown
25
25
  License-File: LICENSE
26
26
  Requires-Dist: PyYAML>=6.0.3
27
- Requires-Dist: httpx>=0.27
28
- Requires-Dist: idna>=3.15
27
+ Requires-Dist: httpx>=0.28
28
+ Requires-Dist: idna>=3.18
29
29
  Requires-Dist: tinycss2>=1.5.1
30
30
  Provides-Extra: pdf
31
- Requires-Dist: weasyprint>=60.0; extra == "pdf"
31
+ Requires-Dist: weasyprint>=69.0; extra == "pdf"
32
32
  Provides-Extra: dev
33
33
  Requires-Dist: pytest; extra == "dev"
34
34
  Requires-Dist: pytest-cov; extra == "dev"
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mkdocs2confluence"
3
- version = "0.17.2"
3
+ version = "0.17.4"
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" }
@@ -31,8 +31,8 @@ classifiers = [
31
31
  ]
32
32
  dependencies = [
33
33
  "PyYAML>=6.0.3",
34
- "httpx>=0.27",
35
- "idna>=3.15",
34
+ "httpx>=0.28",
35
+ "idna>=3.18",
36
36
  "tinycss2>=1.5.1",
37
37
  ]
38
38
 
@@ -44,7 +44,7 @@ Changelog = "https://github.com/jeckyl2010/mkdocs2confluence/releases"
44
44
 
45
45
  [project.optional-dependencies]
46
46
  pdf = [
47
- "weasyprint>=60.0",
47
+ "weasyprint>=69.0",
48
48
  ]
49
49
  dev = [
50
50
  "pytest",
@@ -132,8 +132,8 @@ layers = [
132
132
 
133
133
  [dependency-groups]
134
134
  dev = [
135
- "import-linter>=2.11",
136
- "pip-audit>=2.10.0",
135
+ "import-linter>=2.12",
136
+ "pip-audit>=2.10.1",
137
137
  "radon>=6.0.1",
138
138
  "vulture>=2.16",
139
139
  ]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mkdocs2confluence
3
- Version: 0.17.2
3
+ Version: 0.17.4
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
@@ -24,11 +24,11 @@ Requires-Python: >=3.12
24
24
  Description-Content-Type: text/markdown
25
25
  License-File: LICENSE
26
26
  Requires-Dist: PyYAML>=6.0.3
27
- Requires-Dist: httpx>=0.27
28
- Requires-Dist: idna>=3.15
27
+ Requires-Dist: httpx>=0.28
28
+ Requires-Dist: idna>=3.18
29
29
  Requires-Dist: tinycss2>=1.5.1
30
30
  Provides-Extra: pdf
31
- Requires-Dist: weasyprint>=60.0; extra == "pdf"
31
+ Requires-Dist: weasyprint>=69.0; extra == "pdf"
32
32
  Provides-Extra: dev
33
33
  Requires-Dist: pytest; extra == "dev"
34
34
  Requires-Dist: pytest-cov; extra == "dev"
@@ -16,7 +16,6 @@ src/mkdocs_to_confluence/compiler/page.py
16
16
  src/mkdocs_to_confluence/emitter/__init__.py
17
17
  src/mkdocs_to_confluence/emitter/xhtml.py
18
18
  src/mkdocs_to_confluence/ir/__init__.py
19
- src/mkdocs_to_confluence/ir/document.py
20
19
  src/mkdocs_to_confluence/ir/nodes.py
21
20
  src/mkdocs_to_confluence/ir/treeutil.py
22
21
  src/mkdocs_to_confluence/loader/__init__.py
@@ -46,7 +45,6 @@ src/mkdocs_to_confluence/publisher/client.py
46
45
  src/mkdocs_to_confluence/publisher/executor.py
47
46
  src/mkdocs_to_confluence/publisher/http_retry.py
48
47
  src/mkdocs_to_confluence/publisher/models.py
49
- src/mkdocs_to_confluence/publisher/pipeline.py
50
48
  src/mkdocs_to_confluence/publisher/planner.py
51
49
  src/mkdocs_to_confluence/skills/mkdocs-changelog/SKILL.md
52
50
  src/mkdocs_to_confluence/skills/mkdocs-changelog/scripts/changelog_data.py
@@ -1,6 +1,6 @@
1
1
  PyYAML>=6.0.3
2
- httpx>=0.27
3
- idna>=3.15
2
+ httpx>=0.28
3
+ idna>=3.18
4
4
  tinycss2>=1.5.1
5
5
 
6
6
  [dev]
@@ -14,4 +14,4 @@ build
14
14
  pre-commit
15
15
 
16
16
  [pdf]
17
- weasyprint>=60.0
17
+ weasyprint>=69.0
@@ -9,12 +9,12 @@ import webbrowser
9
9
  from pathlib import Path
10
10
 
11
11
  from mkdocs_to_confluence import __version__
12
+ from mkdocs_to_confluence.compiler.page import compile_page
12
13
  from mkdocs_to_confluence.emitter.xhtml import configure_styles
13
14
  from mkdocs_to_confluence.loader.config import load_config
14
15
  from mkdocs_to_confluence.loader.nav import find_section, find_section_by_folder, flat_pages, resolve_nav
15
16
  from mkdocs_to_confluence.loader.page import PageLoadError, find_page
16
17
  from mkdocs_to_confluence.preview.render import inject_livereload, render_index, render_page
17
- from mkdocs_to_confluence.publisher.pipeline import compile_page
18
18
  from mkdocs_to_confluence.transforms.internallinks import build_link_map
19
19
 
20
20
 
@@ -389,7 +389,7 @@ def _cmd_preview(args: argparse.Namespace) -> None:
389
389
  for node in pages:
390
390
  html_name = page_link_map.get(node.title, f"{Path(node.docs_path or node.title).stem}.html")
391
391
  try:
392
- xhtml, _a, _l, _s, _vm = compile_page(node, config, link_map, quiet=args.quiet)
392
+ xhtml = compile_page(node, config, link_map, quiet=args.quiet).xhtml
393
393
  except PageLoadError as exc:
394
394
  print(f" warning: skipping '{node.title}': {exc}", file=sys.stderr)
395
395
  continue
@@ -447,7 +447,7 @@ def _cmd_preview(args: argparse.Namespace) -> None:
447
447
 
448
448
  def _build_page() -> None:
449
449
  try:
450
- xhtml, _a, _l, _s, _vm = compile_page(page_node, config, link_map, quiet=True)
450
+ xhtml = compile_page(page_node, config, link_map, quiet=True).xhtml
451
451
  except PageLoadError as exc:
452
452
  print(f" warning: {exc}", file=sys.stderr)
453
453
  return
@@ -471,7 +471,7 @@ def _cmd_preview(args: argparse.Namespace) -> None:
471
471
  return
472
472
 
473
473
  try:
474
- xhtml, _attachments, _labels, _status, _vm = compile_page(page_node, config, link_map, quiet=args.quiet)
474
+ xhtml = compile_page(page_node, config, link_map, quiet=args.quiet).xhtml
475
475
  except PageLoadError as exc:
476
476
  print(f"error: {exc}", file=sys.stderr)
477
477
  sys.exit(1)
@@ -553,7 +553,8 @@ def _cmd_publish(args: argparse.Namespace) -> None:
553
553
 
554
554
  from mkdocs_to_confluence.publisher.changelog import publish_changelog
555
555
  from mkdocs_to_confluence.publisher.client import ConfluenceClient, ConfluenceError
556
- from mkdocs_to_confluence.publisher.pipeline import execute_publish, plan_publish
556
+ from mkdocs_to_confluence.publisher.executor import execute_publish
557
+ from mkdocs_to_confluence.publisher.planner import plan_publish
557
558
 
558
559
  try:
559
560
  with ConfluenceClient(conf_config) as client:
@@ -726,7 +727,7 @@ def _cmd_pdf(args: argparse.Namespace) -> None:
726
727
  chapters: list[tuple[str, str]] = []
727
728
  for node in pages:
728
729
  try:
729
- xhtml, _a, _l, _s, _vm = compile_page(node, config, link_map, quiet=args.quiet)
730
+ xhtml = compile_page(node, config, link_map, quiet=args.quiet).xhtml
730
731
  except PageLoadError as exc:
731
732
  print(f" warning: skipping '{node.title}': {exc}", file=sys.stderr)
732
733
  continue
@@ -222,8 +222,12 @@ def _emit_section(node: Section) -> str:
222
222
  if _styles:
223
223
  style_attr = styles_to_attr(_styles.headings.get(f"h{node.level}", {}))
224
224
  anchor = ""
225
- if node.explicit_anchor:
226
- name = html.escape(node.explicit_anchor)
225
+ # Emit an anchor macro for every heading so links resolve to the section.
226
+ # Confluence's auto heading-anchors use a different naming scheme than the
227
+ # MkDocs slug our links carry, so without an explicit named anchor a
228
+ # `#slug` link lands at the top of the page instead of the section.
229
+ name = html.escape(node.explicit_anchor or node.anchor)
230
+ if name:
227
231
  anchor = (
228
232
  f'<ac:structured-macro ac:name="anchor">'
229
233
  f'<ac:parameter ac:name=""><![CDATA[{name}]]></ac:parameter>'
@@ -336,6 +340,9 @@ def _emit_code_block(node: CodeBlock) -> str:
336
340
  parts.append(
337
341
  f' <ac:parameter ac:name="firstline">{node.linenums_start}</ac:parameter>\n'
338
342
  )
343
+ if node.highlight_lines:
344
+ hl = ",".join(str(n) for n in node.highlight_lines)
345
+ parts.append(f' <ac:parameter ac:name="highlight">{hl}</ac:parameter>\n')
339
346
  # Escape ]]> sequences inside CDATA to avoid breaking the block
340
347
  safe_code = node.code.replace("]]>", "]]]]><![CDATA[>")
341
348
  parts.append(f" <ac:plain-text-body><![CDATA[{safe_code}]]></ac:plain-text-body>\n")
@@ -4,12 +4,10 @@ All node types are frozen dataclasses — immutable, hashable, and structurally
4
4
  equal. Import everything you need directly from this package:
5
5
 
6
6
  from mkdocs_to_confluence.ir import (
7
- Document, PageMeta,
8
7
  Section, Paragraph, Text, CodeBlock, ...
9
8
  )
10
9
  """
11
10
 
12
- from mkdocs_to_confluence.ir.document import Document, PageMeta, compute_sha
13
11
  from mkdocs_to_confluence.ir.nodes import (
14
12
  # Material extension nodes
15
13
  Admonition,
@@ -64,10 +62,6 @@ from mkdocs_to_confluence.ir.nodes import (
64
62
  )
65
63
 
66
64
  __all__ = [
67
- # Document envelope
68
- "Document",
69
- "PageMeta",
70
- "compute_sha",
71
65
  # Base
72
66
  "IRNode",
73
67
  "walk",
@@ -216,6 +216,7 @@ class CodeBlock(IRNode):
216
216
  linenums: Whether line numbers are enabled.
217
217
  linenums_start: First line number (default 1); only meaningful when
218
218
  ``linenums`` is ``True``.
219
+ Attributes:
219
220
  highlight_lines: 1-based line numbers that should be highlighted.
220
221
  """
221
222
 
@@ -2,23 +2,22 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import re
5
+ import hashlib
6
6
  import sys
7
7
  from pathlib import Path
8
8
  from typing import TYPE_CHECKING
9
9
 
10
10
  import yaml
11
11
 
12
+ from mkdocs_to_confluence.compiler.page import compile_page
12
13
  from mkdocs_to_confluence.loader.nav import NavNode
13
- from mkdocs_to_confluence.publisher.executor import _upload_assets
14
- from mkdocs_to_confluence.publisher.planner import _xhtml_hash, compile_page
14
+ from mkdocs_to_confluence.preprocess.frontmatter import _FRONT_MATTER_RE
15
+ from mkdocs_to_confluence.publisher.executor import upload_assets
15
16
 
16
17
  if TYPE_CHECKING:
17
18
  from mkdocs_to_confluence.loader.config import ConfluenceConfig, MkDocsConfig
18
19
  from mkdocs_to_confluence.publisher.client import ConfluenceClient
19
20
 
20
- _FRONT_MATTER_RE = re.compile(r"\A---\s*\n(.*?\n?)---\s*\n?", re.DOTALL)
21
-
22
21
 
23
22
  def _extract_title(source_path: Path) -> str | None:
24
23
  """Return the ``title`` value from YAML front matter, or ``None`` if absent."""
@@ -73,11 +72,9 @@ def publish_changelog(
73
72
  if not quiet:
74
73
  print(f" compiling '{title}' (changelog)")
75
74
 
76
- xhtml, attachments, labels, confluence_status, version_message = compile_page(
77
- node, config, link_map or {}, quiet=quiet
78
- )
75
+ result = compile_page(node, config, link_map or {}, quiet=quiet)
79
76
 
80
- xhtml_hash = _xhtml_hash(xhtml)
77
+ xhtml_hash = hashlib.sha256(result.xhtml.encode()).hexdigest()
81
78
  existing = client.find_page(space_id, title)
82
79
 
83
80
  if existing is not None and client.get_content_hash(str(existing["id"])) == xhtml_hash:
@@ -88,7 +85,7 @@ def publish_changelog(
88
85
  parent_id = conf_config.parent_page_id
89
86
 
90
87
  if existing is None:
91
- page = client.create_page(space_id, title, xhtml, parent_id=parent_id)
88
+ page = client.create_page(space_id, title, result.xhtml, parent_id=parent_id)
92
89
  page_id = str(page["id"])
93
90
  # Do NOT stamp as managed: _prune_orphans skips unmanaged pages, so
94
91
  # this ensures --prune never deletes the changelog page.
@@ -98,15 +95,15 @@ def publish_changelog(
98
95
  page_id = str(existing["id"])
99
96
  version: int = existing["version"]["number"]
100
97
  client.update_page(
101
- page_id, title, xhtml, version + 1,
98
+ page_id, title, result.xhtml, version + 1,
102
99
  parent_id=parent_id,
103
- version_message=version_message,
100
+ version_message=result.version_message,
104
101
  )
105
102
  if not quiet:
106
103
  print(f" updated '{title}' (changelog)")
107
104
 
108
- if attachments:
109
- _upload_assets(page_id, attachments, config.docs_dir, client, quiet=quiet)
105
+ if result.attachments:
106
+ upload_assets(page_id, result.attachments, config.docs_dir, client, quiet=quiet)
110
107
 
111
108
  # content hash is an internal optimization; if it fails the next run just
112
109
  # re-publishes, so a failure is self-healing and stays silent.
@@ -119,9 +116,9 @@ def publish_changelog(
119
116
  # never fail an already-saved page (catch broadly so a transient network
120
117
  # error can't abort the publish), but failures are warned so they aren't
121
118
  # invisible — mirroring publisher/executor.py.
122
- if labels:
119
+ if result.labels:
123
120
  try:
124
- client.set_page_labels(page_id, labels)
121
+ client.set_page_labels(page_id, result.labels)
125
122
  except Exception as exc:
126
123
  print(f" [warn] changelog: could not set labels: {exc}", file=sys.stderr)
127
124
 
@@ -131,12 +128,12 @@ def publish_changelog(
131
128
  except Exception as exc:
132
129
  print(f" [warn] changelog: could not set full-width: {exc}", file=sys.stderr)
133
130
 
134
- if confluence_status:
131
+ if result.confluence_status:
135
132
  try:
136
- client.set_page_status(page_id, confluence_status, space_key=space_key)
133
+ client.set_page_status(page_id, result.confluence_status, space_key=space_key)
137
134
  except Exception as exc:
138
135
  print(
139
136
  f" [warn] changelog: could not set page status "
140
- f"{confluence_status!r}: {exc}",
137
+ f"{result.confluence_status!r}: {exc}",
141
138
  file=sys.stderr,
142
139
  )
@@ -9,13 +9,13 @@ from typing import TYPE_CHECKING
9
9
 
10
10
  from mkdocs_to_confluence.publisher.client import ConfluenceError
11
11
  from mkdocs_to_confluence.publisher.models import PageAction, PublishReport
12
- from mkdocs_to_confluence.transforms.assets import _make_attachment_name
12
+ from mkdocs_to_confluence.transforms.assets import make_attachment_name
13
13
 
14
14
  if TYPE_CHECKING:
15
15
  from mkdocs_to_confluence.publisher.client import ConfluenceClient
16
16
 
17
17
 
18
- def _upload_assets(
18
+ def upload_assets(
19
19
  page_id: str,
20
20
  attachments: list[Path],
21
21
  docs_dir: Path,
@@ -24,7 +24,7 @@ def _upload_assets(
24
24
  quiet: bool = False,
25
25
  ) -> tuple[int, int, list[tuple[str, str]]]:
26
26
  """Upload attachments for one page sequentially."""
27
- pairs = [(_make_attachment_name(p, docs_dir), p) for p in attachments]
27
+ pairs = [(make_attachment_name(p, docs_dir), p) for p in attachments]
28
28
  uploaded = 0
29
29
  skipped = 0
30
30
  errors: list[tuple[str, str]] = []
@@ -271,7 +271,7 @@ def _post_process_action(
271
271
 
272
272
  # Upload assets — skip files whose mtime is not newer than Confluence.
273
273
  if action.page_id and action.attachments:
274
- uploaded, asset_skipped, asset_errors = _upload_assets(
274
+ uploaded, asset_skipped, asset_errors = upload_assets(
275
275
  action.page_id, action.attachments, docs_dir, client, quiet=quiet
276
276
  )
277
277
  report.assets_uploaded += uploaded
@@ -3,17 +3,17 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import hashlib
6
- import re
7
6
  import sys
8
7
  from pathlib import Path
9
8
  from typing import TYPE_CHECKING
10
9
 
11
10
  import yaml
12
11
 
13
- from mkdocs_to_confluence.compiler.page import compile_page as _compile_page_result
12
+ from mkdocs_to_confluence.compiler.page import compile_page
14
13
  from mkdocs_to_confluence.loader.config import ConfluenceConfig, MkDocsConfig
15
14
  from mkdocs_to_confluence.loader.nav import NavNode
16
15
  from mkdocs_to_confluence.loader.page import PageLoadError
16
+ from mkdocs_to_confluence.preprocess.frontmatter import _FRONT_MATTER_RE
17
17
  from mkdocs_to_confluence.preprocess.icons import strip_icon_shortcodes
18
18
  from mkdocs_to_confluence.publisher.models import PageAction
19
19
  from mkdocs_to_confluence.transforms.internallinks import build_link_map
@@ -21,8 +21,6 @@ from mkdocs_to_confluence.transforms.internallinks import build_link_map
21
21
  if TYPE_CHECKING:
22
22
  from mkdocs_to_confluence.publisher.client import ConfluenceClient
23
23
 
24
- _FRONT_MATTER_RE = re.compile(r"\A---\s*\n(.*?\n?)---\s*\n?", re.DOTALL)
25
-
26
24
 
27
25
  def _extract_ready_flag(raw: str) -> bool | None:
28
26
  """Return the ``ready`` value from front matter, or ``None`` if absent."""
@@ -41,36 +39,6 @@ def _extract_ready_flag(raw: str) -> bool | None:
41
39
  return bool(val)
42
40
 
43
41
 
44
- def compile_page(
45
- node: NavNode,
46
- config: MkDocsConfig,
47
- link_map: dict[str, str] | None = None,
48
- *,
49
- is_section_index: bool = False,
50
- quiet: bool = False,
51
- ) -> tuple[str, list[Path], tuple[str, ...], str | None, str | None]:
52
- """Compatibility wrapper around the compiler module's typed page compiler."""
53
- result = _compile_page_result(
54
- node,
55
- config,
56
- link_map,
57
- is_section_index=is_section_index,
58
- quiet=quiet,
59
- )
60
- return (
61
- result.xhtml,
62
- result.attachments,
63
- result.labels,
64
- result.confluence_status,
65
- result.version_message,
66
- )
67
-
68
-
69
- def _xhtml_hash(xhtml: str) -> str:
70
- """Return a stable sha256 hex digest of the emitted XHTML string."""
71
- return hashlib.sha256(xhtml.encode()).hexdigest()
72
-
73
-
74
42
  def _find_section_index(node: NavNode) -> NavNode | None:
75
43
  """Return the first direct child whose docs_path ends with 'index.md'."""
76
44
  for child in node.children:
@@ -96,7 +64,7 @@ def _plan_compiled_page_action(
96
64
  ) -> PageAction:
97
65
  """Build the PageAction for a compiled page or section index."""
98
66
  existing = client.find_page(space_id, title)
99
- xhtml_h = _xhtml_hash(xhtml)
67
+ xhtml_h = hashlib.sha256(xhtml.encode()).hexdigest()
100
68
  if existing is not None and client.get_content_hash(str(existing["id"])) == xhtml_h:
101
69
  if not quiet:
102
70
  print(f" unchanged '{title}' (content unchanged)")
@@ -190,7 +158,7 @@ def _plan_nodes(
190
158
  if not quiet:
191
159
  print(f" compiling '{clean_title}' (section index)")
192
160
  try:
193
- xhtml, attachments, labels, confluence_status, version_message = compile_page(
161
+ result = compile_page(
194
162
  index_child, config, link_map, is_section_index=True, quiet=quiet
195
163
  )
196
164
  page_action = _plan_compiled_page_action(
@@ -200,11 +168,11 @@ def _plan_nodes(
200
168
  title=clean_title,
201
169
  parent_id=parent_id,
202
170
  parent_is_folder=parent_is_folder,
203
- xhtml=xhtml,
204
- attachments=attachments,
205
- labels=labels,
206
- confluence_status=confluence_status,
207
- version_message=version_message,
171
+ xhtml=result.xhtml,
172
+ attachments=result.attachments,
173
+ labels=result.labels,
174
+ confluence_status=result.confluence_status,
175
+ version_message=result.version_message,
208
176
  quiet=quiet,
209
177
  )
210
178
  actions.append(page_action)
@@ -275,9 +243,7 @@ def _plan_nodes(
275
243
  if not quiet:
276
244
  print(f" compiling '{clean_title}'")
277
245
  try:
278
- xhtml, attachments, labels, confluence_status, version_message = compile_page(
279
- node, config, link_map, quiet=quiet
280
- )
246
+ result = compile_page(node, config, link_map, quiet=quiet)
281
247
  except (PageLoadError, OSError) as exc:
282
248
  if not quiet:
283
249
  print(f" skipping '{clean_title}' (error: {exc})")
@@ -298,11 +264,11 @@ def _plan_nodes(
298
264
  title=clean_title,
299
265
  parent_id=parent_id,
300
266
  parent_is_folder=False,
301
- xhtml=xhtml,
302
- attachments=attachments,
303
- labels=labels,
304
- confluence_status=confluence_status,
305
- version_message=version_message,
267
+ xhtml=result.xhtml,
268
+ attachments=result.attachments,
269
+ labels=result.labels,
270
+ confluence_status=result.confluence_status,
271
+ version_message=result.version_message,
306
272
  quiet=quiet,
307
273
  )
308
274
  actions.append(page_action)
@@ -1,7 +1,7 @@
1
1
  """Generic Kroki diagram rendering utilities shared by all diagram transforms.
2
2
 
3
3
  Provides:
4
- - :func:`kroki_post_png` — low-level HTTP POST to Kroki for any diagram type.
4
+ - :func:`kroki_post` — low-level HTTP POST to Kroki for any diagram type and format.
5
5
  - :func:`render_diagrams` — concurrent deduplication/replacement loop used by
6
6
  every diagram-type transform. Each transform supplies its own ``render_fn``
7
7
  that handles type-specific caching and retry behaviour.
@@ -46,16 +46,19 @@ class _DiagramNode(Protocol):
46
46
  _D = TypeVar("_D", bound="_DiagramNode")
47
47
 
48
48
 
49
- def kroki_post_png(source: str, diagram_type: str, kroki_url: str) -> bytes:
50
- """POST *source* to Kroki for *diagram_type* and return PNG bytes."""
51
- url = f"{kroki_url.rstrip('/')}/{diagram_type}/png"
49
+ _ACCEPT: dict[str, str] = {"png": "image/png", "svg": "image/svg+xml"}
50
+
51
+
52
+ def kroki_post(source: str, diagram_type: str, kroki_url: str, fmt: str = "png") -> bytes:
53
+ """POST *source* to Kroki for *diagram_type* and return rendered bytes."""
54
+ url = f"{kroki_url.rstrip('/')}/{diagram_type}/{fmt}"
52
55
  body = source.encode("utf-8")
53
56
  req = urllib.request.Request(
54
57
  url,
55
58
  data=body,
56
59
  headers={
57
60
  "Content-Type": "text/plain",
58
- "Accept": "image/png",
61
+ "Accept": _ACCEPT.get(fmt, f"image/{fmt}"),
59
62
  "User-Agent": "mk2conf/1.0",
60
63
  },
61
64
  method="POST",
@@ -14,10 +14,10 @@ from __future__ import annotations
14
14
 
15
15
  import dataclasses
16
16
  import re
17
- import sys
18
17
 
19
18
  from mkdocs_to_confluence.ir.nodes import Admonition, IRNode, walk
20
19
  from mkdocs_to_confluence.ir.treeutil import replace_nodes
20
+ from mkdocs_to_confluence.transforms._kroki import warn as _warn
21
21
 
22
22
  # Inline Markdown link [text](target), but not an image (no leading '!').
23
23
  _LINK_RE = re.compile(r"(?<!!)\[([^\]]+)\]\(([^)]+)\)")
@@ -50,6 +50,3 @@ def strip_links_in_admonition_titles(
50
50
  return nodes
51
51
  return replace_nodes(nodes, replacements)
52
52
 
53
-
54
- def _warn(msg: str) -> None:
55
- print(f" warning {msg}", file=sys.stderr)
@@ -31,7 +31,7 @@ def is_url(value: str) -> bool:
31
31
  return value.startswith(("http://", "https://", "//", "data:"))
32
32
 
33
33
 
34
- def _make_attachment_name(abs_path: Path, docs_dir: Path) -> str:
34
+ def make_attachment_name(abs_path: Path, docs_dir: Path) -> str:
35
35
  """Compute a collision-safe attachment filename from an absolute path.
36
36
 
37
37
  Joins the path parts relative to ``docs_dir`` with underscores so that
@@ -83,7 +83,7 @@ def resolve_local_assets(
83
83
  candidate = _resolve_asset_path(node.src, page_dir, docs_dir)
84
84
  if candidate is None:
85
85
  continue
86
- attachment_name = _make_attachment_name(candidate, docs_dir)
86
+ attachment_name = make_attachment_name(candidate, docs_dir)
87
87
  if candidate not in seen:
88
88
  seen[candidate] = None
89
89
  attachments.append(candidate)
@@ -114,7 +114,7 @@ def resolve_local_assets(
114
114
  stacklevel=2,
115
115
  )
116
116
  continue
117
- attachment_name = _make_attachment_name(candidate, docs_dir)
117
+ attachment_name = make_attachment_name(candidate, docs_dir)
118
118
  if candidate not in seen:
119
119
  seen[candidate] = None
120
120
  attachments.append(candidate)
@@ -25,7 +25,6 @@ from __future__ import annotations
25
25
  import base64
26
26
  import hashlib
27
27
  import json
28
- import sys
29
28
  import time
30
29
  import urllib.error
31
30
  import urllib.request
@@ -42,31 +41,17 @@ from mkdocs_to_confluence.transforms._kroki import (
42
41
  _RETRYABLE_HTTP,
43
42
  _TIMEOUT,
44
43
  DEFAULT_KROKI_URL,
44
+ kroki_post,
45
45
  render_diagrams,
46
46
  )
47
+ from mkdocs_to_confluence.transforms._kroki import (
48
+ warn as _warn,
49
+ )
47
50
 
48
51
  _CACHE_DIR = Path.home() / ".cache" / "mk2conf" / "mermaid"
49
52
  _MERMAID_INK_URL = "https://mermaid.ink"
50
53
 
51
54
 
52
- def _kroki_png(source: str, kroki_url: str) -> bytes:
53
- """Fetch a PNG rendering of *source* from the Kroki service (POST)."""
54
- url = f"{kroki_url.rstrip('/')}/mermaid/png"
55
- body = source.encode("utf-8")
56
- req = urllib.request.Request(
57
- url,
58
- data=body,
59
- headers={
60
- "Content-Type": "text/plain",
61
- "Accept": "image/png",
62
- "User-Agent": "mk2conf/1.0",
63
- },
64
- method="POST",
65
- )
66
- with urllib.request.urlopen(req, timeout=_TIMEOUT) as resp: # noqa: S310 # nosec B310
67
- return cast(bytes, resp.read())
68
-
69
-
70
55
  def _mermaid_ink_png(source: str) -> bytes:
71
56
  """Fetch a PNG rendering of *source* from mermaid.ink (GET, pako-encoded).
72
57
 
@@ -87,10 +72,6 @@ def _cache_path(source: str) -> Path:
87
72
  return _CACHE_DIR / f"mermaid_{digest}.png"
88
73
 
89
74
 
90
- def _warn(msg: str) -> None:
91
- print(f" warning {msg}", file=sys.stderr)
92
-
93
-
94
75
  def _render_one(source: str, kroki_url: str, *, quiet: bool = False) -> Path | None:
95
76
  """Render a single diagram to cache. Returns cache path on success, None on failure.
96
77
 
@@ -120,7 +101,7 @@ def _render_one(source: str, kroki_url: str, *, quiet: bool = False) -> Path | N
120
101
  try:
121
102
  if not quiet:
122
103
  print(f" rendering mermaid diagram via Kroki ({kroki_url})")
123
- png = _kroki_png(source, kroki_url)
104
+ png = kroki_post(source, "mermaid", kroki_url)
124
105
  if len(png) < _MIN_PNG_BYTES:
125
106
  raise ValueError(f"Kroki returned {len(png)} bytes (expected a valid PNG)")
126
107
  with _CACHE_LOCK: