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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. {markdown_to_confluence-0.5.1.dist-info → markdown_to_confluence-0.5.3.dist-info}/METADATA +160 -11
  2. markdown_to_confluence-0.5.3.dist-info/RECORD +55 -0
  3. {markdown_to_confluence-0.5.1.dist-info → markdown_to_confluence-0.5.3.dist-info}/licenses/LICENSE +1 -1
  4. md2conf/__init__.py +2 -2
  5. md2conf/__main__.py +94 -29
  6. md2conf/api.py +55 -10
  7. md2conf/attachment.py +72 -0
  8. md2conf/coalesce.py +43 -0
  9. md2conf/collection.py +1 -1
  10. md2conf/{extra.py → compatibility.py} +1 -1
  11. md2conf/converter.py +417 -590
  12. md2conf/csf.py +13 -11
  13. md2conf/drawio/__init__.py +0 -0
  14. md2conf/drawio/extension.py +116 -0
  15. md2conf/{drawio.py → drawio/render.py} +1 -1
  16. md2conf/emoticon.py +3 -3
  17. md2conf/environment.py +2 -2
  18. md2conf/extension.py +78 -0
  19. md2conf/external.py +49 -0
  20. md2conf/formatting.py +135 -0
  21. md2conf/frontmatter.py +70 -0
  22. md2conf/image.py +127 -0
  23. md2conf/latex.py +7 -186
  24. md2conf/local.py +8 -8
  25. md2conf/markdown.py +1 -1
  26. md2conf/matcher.py +1 -1
  27. md2conf/mermaid/__init__.py +0 -0
  28. md2conf/mermaid/config.py +20 -0
  29. md2conf/mermaid/extension.py +109 -0
  30. md2conf/{mermaid.py → mermaid/render.py} +10 -38
  31. md2conf/mermaid/scanner.py +55 -0
  32. md2conf/metadata.py +1 -1
  33. md2conf/options.py +116 -0
  34. md2conf/plantuml/__init__.py +0 -0
  35. md2conf/plantuml/config.py +20 -0
  36. md2conf/plantuml/extension.py +158 -0
  37. md2conf/plantuml/render.py +139 -0
  38. md2conf/plantuml/scanner.py +56 -0
  39. md2conf/png.py +202 -0
  40. md2conf/processor.py +32 -11
  41. md2conf/publisher.py +17 -18
  42. md2conf/scanner.py +31 -128
  43. md2conf/serializer.py +2 -2
  44. md2conf/svg.py +341 -0
  45. md2conf/text.py +1 -1
  46. md2conf/toc.py +1 -1
  47. md2conf/uri.py +1 -1
  48. md2conf/xml.py +1 -1
  49. markdown_to_confluence-0.5.1.dist-info/RECORD +0 -35
  50. md2conf/domain.py +0 -52
  51. {markdown_to_confluence-0.5.1.dist-info → markdown_to_confluence-0.5.3.dist-info}/WHEEL +0 -0
  52. {markdown_to_confluence-0.5.1.dist-info → markdown_to_confluence-0.5.3.dist-info}/entry_points.txt +0 -0
  53. {markdown_to_confluence-0.5.1.dist-info → markdown_to_confluence-0.5.3.dist-info}/top_level.txt +0 -0
  54. {markdown_to_confluence-0.5.1.dist-info → markdown_to_confluence-0.5.3.dist-info}/zip-safe +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: markdown-to-confluence
3
- Version: 0.5.1
3
+ Version: 0.5.3
4
4
  Summary: Publish Markdown files to Confluence wiki
5
5
  Author-email: Levente Hunyadi <hunyadi@gmail.com>
6
6
  Maintainer-email: Levente Hunyadi <hunyadi@gmail.com>
@@ -27,18 +27,18 @@ Requires-Dist: cattrs>=25.3
27
27
  Requires-Dist: lxml>=6.0
28
28
  Requires-Dist: markdown>=3.10
29
29
  Requires-Dist: orjson>=3.11
30
- Requires-Dist: pymdown-extensions>=10.17
30
+ Requires-Dist: pymdown-extensions>=10.19
31
31
  Requires-Dist: PyYAML>=6.0
32
32
  Requires-Dist: requests>=2.32
33
33
  Requires-Dist: truststore>=0.10
34
34
  Requires-Dist: typing-extensions>=4.15; python_version < "3.12"
35
35
  Provides-Extra: dev
36
- Requires-Dist: markdown_doc>=0.1.5; extra == "dev"
37
- Requires-Dist: types-lxml>=2025.8.25; extra == "dev"
36
+ Requires-Dist: markdown_doc>=0.1.6; extra == "dev"
37
+ Requires-Dist: types-lxml>=2025.11.25; extra == "dev"
38
38
  Requires-Dist: types-markdown>=3.10; extra == "dev"
39
39
  Requires-Dist: types-PyYAML>=6.0; extra == "dev"
40
40
  Requires-Dist: types-requests>=2.32; extra == "dev"
41
- Requires-Dist: mypy>=1.18; extra == "dev"
41
+ Requires-Dist: mypy>=1.19; extra == "dev"
42
42
  Requires-Dist: ruff>=0.14; extra == "dev"
43
43
  Provides-Extra: formulas
44
44
  Requires-Dist: matplotlib>=3.9; extra == "formulas"
@@ -98,6 +98,15 @@ pip install markdown-to-confluence
98
98
  npm install -g @mermaid-js/mermaid-cli
99
99
  ```
100
100
 
101
+ **Optional.** Pre-rendering PlantUML diagrams into PNG or SVG images requires Java, Graphviz and [PlantUML](https://plantuml.com/). (Refer to `--render-plantuml`.)
102
+
103
+ 1. **Install Java**: Version 8 or later from [Adoptium](https://adoptium.net/) or [Oracle](https://www.oracle.com/java/technologies/downloads/)
104
+ 2. **Install Graphviz**: Required for most diagram types in PlantUML (except sequence diagrams)
105
+ * **Ubuntu/Debian**: `sudo apt-get install Graphviz`
106
+ * **macOS**: `brew install graphviz`
107
+ * **Windows**: Download from [graphviz.org](https://graphviz.org/download/)
108
+ 3. **Download PlantUML JAR**: Download [plantuml.jar](https://github.com/plantuml/plantuml/releases) and set `PLANTUML_JAR` environment variable to point to it
109
+
101
110
  **Optional.** Converting formulas and equations to PNG or SVG images requires [Matplotlib](https://matplotlib.org/):
102
111
 
103
112
  ```sh
@@ -112,7 +121,11 @@ As authors of *md2conf*, we don't endorse or support any particular Confluence m
112
121
 
113
122
  **Optional.** Displaying Mermaid diagrams in Confluence without pre-rendering in the synchronization phase requires a [marketplace app](https://marketplace.atlassian.com/apps/1226567/mermaid-diagrams-for-confluence). (Refer to `--no-render-mermaid`.)
114
123
 
115
- **Optional.** Displaying formulas and equations in Confluence requires [marketplace app](https://marketplace.atlassian.com/apps/1226109/latex-math-for-confluence-math-formula-equations), refer to [LaTeX Math for Confluence - Math Formula & Equations](https://help.narva.net/latex-math-for-confluence/).
124
+ **Optional.** PlantUML diagrams are embedded with compressed source data and are displayed using the [PlantUML Diagrams for Confluence](https://marketplace.atlassian.com/apps/1215115/plantuml-diagrams-for-confluence) app (if installed). (Refer to `--no-render-plantuml`.)
125
+
126
+ Installing `plantuml.jar` (see above) helps display embedded diagrams with pre-calculated optimal dimensions.
127
+
128
+ **Optional.** Displaying formulas and equations in Confluence requires [marketplace app](https://marketplace.atlassian.com/apps/1226109/latex-math-for-confluence-math-formula-equations), refer to [LaTeX Math for Confluence - Math Formula & Equations](https://help.narva.net/latex-math-for-confluence/). (Refer to `--no-render-latex`.)
116
129
 
117
130
  ## Getting started
118
131
 
@@ -215,6 +228,21 @@ Provide generated-by prompt text in the Markdown file with a tag:
215
228
 
216
229
  Alternatively, use the `--generated-by GENERATED_BY` option. The tag takes precedence.
217
230
 
231
+ The generated-by text can also be templated with the following variables:
232
+
233
+ - `%{filename}`: the name of the Markdown file
234
+ - `%{filestem}`: the name of the Markdown file without the extension
235
+ - `%{filepath}`: the path of the Markdown file relative to the _source root_
236
+ - `%{filedir}`: the dirname of the `%{filepath}` (the path without the filename)
237
+
238
+ When publishing a directory hierarchy, the *source root* is the directory in which *md2conf* is launched. When publishing a single file, this is the directory in which the Markdown file resides.
239
+
240
+ It can be used with the CLI `--generated-by` option or directly in the files:
241
+
242
+ ```markdown
243
+ <!-- generated-by: Do not edit! Check out the file %{filepath} in the repo -->
244
+ ```
245
+
218
246
  ### Publishing a single page
219
247
 
220
248
  *md2conf* has two modes of operation: *single-page mode* and *directory mode*.
@@ -359,6 +387,11 @@ Likewise, if you have a nested list, make sure that nested items are indented by
359
387
 
360
388
  Local images referenced in a Markdown file are automatically published to Confluence as attachments to the page.
361
389
 
390
+ * Relative paths (e.g. `path/to/image.png` or `../to/image.png`) resolve to absolute paths w.r.t. the Markdown document location.
391
+ * Absolute paths (e.g. `/path/to/image.png`) are interpreted w.r.t. to the synchronization root (typically the shell current directory).
392
+
393
+ As a security measure, resolved paths can only reference files that are in the directory hierarchy of the synchronization root; you can't use `..` to leave the top-level directory of the synchronization root.
394
+
362
395
  Unfortunately, Confluence struggles with SVG images, e.g. they may only show in *edit* mode, display in a wrong size or text labels in the image may be truncated. (This seems to be a known issue in Confluence.) In order to mitigate the issue, whenever *md2conf* encounters a reference to an SVG image in a Markdown file, it checks whether a corresponding PNG image also exists in the same directory, and if a PNG image is found, it is published instead.
363
396
 
364
397
  External images referenced with an absolute URL retain the original URL.
@@ -455,6 +488,58 @@ This is useful if you have a page in a hierarchy that participates in parent-chi
455
488
 
456
489
  If the `title` attribute (in the front-matter) or the topmost unique heading (in the document body) changes, the Confluence page title is updated. A warning is raised if the new title conflicts with the title of another page, and thus cannot be updated.
457
490
 
491
+ #### Avoiding duplicate titles
492
+
493
+ By default, when *md2conf* extracts a page title from the first unique heading in a Markdown document, the heading remains in the document body. This means the title appears twice on the Confluence page: once as the page title at the top, and once as the first heading in the content.
494
+
495
+ To avoid this duplication, use the `--skip-title-heading` option. When enabled, *md2conf* removes the first heading from the document body if it was used as the page title. This option only takes effect when:
496
+
497
+ 1. The title was extracted from the document's first unique heading (not from front-matter), AND
498
+ 2. There is exactly one top-level heading in the document.
499
+
500
+ If the title comes from the `title` attribute in front-matter, the heading is preserved in the document body regardless of this setting, as the heading and title are considered separate.
501
+
502
+ **Example without `--skip-title-heading` (default):**
503
+
504
+ Markdown:
505
+ ```markdown
506
+ # Installation Guide
507
+
508
+ Follow these steps...
509
+ ```
510
+
511
+ Confluence displays:
512
+ - Page title: "Installation Guide"
513
+ - Content: Starts with heading "Installation Guide", followed by "Follow these steps..."
514
+
515
+ **Example with `--skip-title-heading`:**
516
+
517
+ Same Markdown source, but Confluence displays:
518
+ - Page title: "Installation Guide"
519
+ - Content: Starts directly with "Follow these steps..." (heading removed)
520
+
521
+ **Edge case: Abstract or introductory text before the title:**
522
+
523
+ When a document has content before the first heading (like an abstract), removing the heading eliminates the visual separator between the introductory text and the main content:
524
+
525
+ ```markdown
526
+ This is an abstract paragraph providing context.
527
+
528
+ # Document Title
529
+
530
+ This is the main document content.
531
+ ```
532
+
533
+ With `--skip-title-heading`, the output becomes:
534
+ - Page title: "Document Title"
535
+ - Content: "This is an abstract paragraph..." flows directly into "This is the main document content..." (no heading separator)
536
+
537
+ While the structure remains semantically correct, the visual separation is lost. If you need to maintain separation, consider these workarounds:
538
+
539
+ 1. **Use a horizontal rule:** Add `---` after the abstract to create visual separation
540
+ 2. **Use an admonition block:** Wrap the abstract in an info/note block
541
+ 3. **Use front-matter title:** Set `title` in front-matter to keep the heading in the body
542
+
458
543
  ### Labels
459
544
 
460
545
  If a Markdown document has the front-matter attribute `tags`, *md2conf* assigns the specified tags to the Confluence page as labels.
@@ -540,7 +625,9 @@ Specifically, image references for status labels (e.g. `![My label][STATUS-RED]`
540
625
 
541
626
  ### Running the tool
542
627
 
543
- You execute the command-line tool `md2conf` to synchronize the Markdown file with Confluence:
628
+ #### Command line
629
+
630
+ You can synchronize a (directory of) Markdown file(s) with Confluence using the command-line tool `md2conf`:
544
631
 
545
632
  ```sh
546
633
  $ python3 -m md2conf sample/index.md
@@ -571,27 +658,89 @@ options:
571
658
  -r ROOT_PAGE Root Confluence page to create new pages. If omitted, will raise exception when creating new pages.
572
659
  --keep-hierarchy Maintain source directory structure when exporting to Confluence.
573
660
  --flatten-hierarchy Flatten directories with no index.md or README.md when exporting to Confluence.
574
- --generated-by GENERATED_BY
661
+ --generated-by MARKDOWN
575
662
  Add prompt to pages (default: 'This page has been generated with a tool.').
576
663
  --no-generated-by Do not add 'generated by a tool' prompt to pages.
577
664
  --render-drawio Render draw.io diagrams as image files. (Installed utility required to covert.)
578
665
  --no-render-drawio Upload draw.io diagram sources as Confluence page attachments. (Marketplace app required to display.)
579
666
  --render-mermaid Render Mermaid diagrams as image files. (Installed utility required to convert.)
580
667
  --no-render-mermaid Upload Mermaid diagram sources as Confluence page attachments. (Marketplace app required to display.)
668
+ --render-plantuml Render PlantUML diagrams as image files. (Installed utility required to convert.)
669
+ --no-render-plantuml Upload PlantUML diagram sources as Confluence page attachments. (Marketplace app required to display.)
581
670
  --render-latex Render LaTeX formulas as image files. (Matplotlib required to convert.)
582
671
  --no-render-latex Inline LaTeX formulas in Confluence page. (Marketplace app required to display.)
583
672
  --diagram-output-format {png,svg}
584
673
  Format for rendering Mermaid and draw.io diagrams (default: 'png').
674
+ --prefer-raster Prefer PNG over SVG when both exist (default: enabled).
675
+ --no-prefer-raster Use SVG files directly instead of preferring PNG equivalents.
585
676
  --heading-anchors Place an anchor at each section heading with GitHub-style same-page identifiers.
586
677
  --no-heading-anchors Don't place an anchor at each section heading.
587
678
  --ignore-invalid-url Emit a warning but otherwise ignore relative URLs that point to ill-specified locations.
588
- --local Write XHTML-based Confluence Storage Format files locally without invoking Confluence API.
589
- --headers KEY=VALUE [KEY=VALUE ...]
590
- Apply custom headers to all Confluence API requests.
679
+ --skip-title-heading Skip the first heading from document body when it is used as the page title (does not apply if title comes from front-matter).
680
+ --no-skip-title-heading
681
+ Keep the first heading in document body even when used as page title (default).
682
+ --title-prefix TEXT String to prepend to Confluence page title for each published page.
591
683
  --webui-links Enable Confluence Web UI links. (Typically required for on-prem versions of Confluence.)
592
684
  --alignment {center,left,right}
593
685
  Alignment for block-level images and formulas (default: 'center').
686
+ --max-image-width MAX_IMAGE_WIDTH
687
+ Maximum display width for images [px]. Wider images are scaled down for page display. Original size kept for full-size viewing.
594
688
  --use-panel Transform admonitions and alerts into a Confluence custom panel.
689
+ --local Write XHTML-based Confluence Storage Format files locally without invoking Confluence API.
690
+ --headers KEY=VALUE [KEY=VALUE ...]
691
+ Apply custom headers to all Confluence API requests.
692
+ ```
693
+
694
+ #### Python
695
+
696
+ *md2conf* has a Python interface. Create a `ConnectionProperties` object to set connection parameters to the Confluence server, and a `DocumentOptions` object to configure how Markdown files are converted into pages on a Confluence wiki site. Open a connection to the Confluence server with the context manager `ConfluenceAPI`, and instantiate a `Publisher` to start converting documents.
697
+
698
+ ```python
699
+ from md2conf.api import ConfluenceAPI
700
+ from md2conf.environment import ConnectionProperties
701
+ from md2conf.options import ConverterOptions, DocumentOptions, ImageLayoutOptions, LayoutOptions, TableLayoutOptions
702
+ from md2conf.publisher import Publisher
703
+
704
+ properties = ConnectionProperties(
705
+ api_url=...,
706
+ domain=...,
707
+ base_path=...,
708
+ user_name=...,
709
+ api_key=...,
710
+ space_key=...,
711
+ headers=...,
712
+ )
713
+ options = DocumentOptions(
714
+ root_page_id=...,
715
+ keep_hierarchy=...,
716
+ title_prefix=...,
717
+ generated_by=...,
718
+ converter=ConverterOptions(
719
+ heading_anchors=...,
720
+ ignore_invalid_url=...,
721
+ skip_title_heading=...,
722
+ prefer_raster=...,
723
+ render_drawio=...,
724
+ render_mermaid=...,
725
+ render_plantuml=...,
726
+ render_latex=...,
727
+ diagram_output_format=...,
728
+ webui_links=...,
729
+ use_panel=...,
730
+ layout=LayoutOptions(
731
+ image=ImageLayoutOptions(
732
+ alignment=...,
733
+ max_width=...,
734
+ ),
735
+ table=TableLayoutOptions(
736
+ width=...,
737
+ display_mode=...,
738
+ ),
739
+ ),
740
+ ),
741
+ )
742
+ with ConfluenceAPI(properties) as api:
743
+ Publisher(api, options).process(mdpath)
595
744
  ```
596
745
 
597
746
  ### Confluence REST API v1 vs. v2
@@ -0,0 +1,55 @@
1
+ markdown_to_confluence-0.5.3.dist-info/licenses/LICENSE,sha256=SEEBf2BMI1LUHnDvyHnV6L12A6zTAOQcsyMvaawAXWo,1077
2
+ md2conf/__init__.py,sha256=CqQHkYFE1AAs4GhMm1nConbt3V7wksgDXzqm5mg6F6I,402
3
+ md2conf/__main__.py,sha256=Wxz6Rx1Sx_J0FbaCY2HpByHqTMbxDEs1v5VzfdQh32U,13891
4
+ md2conf/api.py,sha256=GVPElSP9qILA5IaEvtKaxjsoRQSsGMMoRhCxjjzLadM,42703
5
+ md2conf/attachment.py,sha256=Nc3qGDENWBnsI6OVwMLXnk0EyEITpvov9MluDFD90ZI,1689
6
+ md2conf/coalesce.py,sha256=YHnqFwow5wCj6OQ3oosig01D2lxWusAScMF4HAUO2-g,1305
7
+ md2conf/collection.py,sha256=ukN74VCa4HaGSh6tLXpLd0j_UNPywcnKI0X7usgdSCo,824
8
+ md2conf/compatibility.py,sha256=4ZNN6VLqxSbI1kowdsPproGZqwxBISys4Z22vBfe6Z8,687
9
+ md2conf/converter.py,sha256=C6cROI8bUswyNZ1jSC0lf_9J-S6ojrXLbrkSDALuKR8,63065
10
+ md2conf/csf.py,sha256=6H9G-5cZyyWMJr0tFskPNiWdQ2Ehq-V8EhlvvxhukWY,6582
11
+ md2conf/emoticon.py,sha256=0g4rkx3d58xU4nnLak5ms7i0FSDnq0WJrLVFRgGyLC8,542
12
+ md2conf/entities.dtd,sha256=M6NzqL5N7dPs_eUA_6sDsiSLzDaAacrx9LdttiufvYU,30215
13
+ md2conf/environment.py,sha256=TfNEz3Pyw9qe7f8i7e_kph16c09fhZ4cLNZZzIjmI18,3892
14
+ md2conf/extension.py,sha256=5d2CtfULwiqlqwpOqbvlVu2KQ-kVBkDDYAhnHXbq79I,2227
15
+ md2conf/external.py,sha256=ZRL0mCY02Gp4XfqRdbap2YdOihSpY2LA6tdGJBfC-FQ,1693
16
+ md2conf/formatting.py,sha256=ygL59VgpioX069axEX-7XjKs0sUjTfIZiBE5fWmITxc,4557
17
+ md2conf/frontmatter.py,sha256=iWtn_oXoLQxvCsdI3OXs1ylWGmB-gc7mMLpSGg113i4,1888
18
+ md2conf/image.py,sha256=udlnUY_xOmI-PJAqWqXBF7hAO3pj_VW7u5hXhBw4HcA,5260
19
+ md2conf/latex.py,sha256=haZKkUxSEcPj3fVmiIVZAwgszqNqGLk1GQ7i8KGHpo0,2226
20
+ md2conf/local.py,sha256=eY3WpY-lNzLZeAfxX1ACVEhuzz0HDYX_sNQogJfkqcM,3673
21
+ md2conf/markdown.py,sha256=4Km-AbQH04nDgPF0ijo-Ld7o8jTPXzENIMn7P1qIk0o,3148
22
+ md2conf/matcher.py,sha256=Xg4YSb87iPkCzhKuKytBut6NOkEab3IM-AjzXbwy64U,6774
23
+ md2conf/metadata.py,sha256=NOjbCIrwLgTIIeNgmo7w5JXuT-pxOXBGSg-irfdpokk,976
24
+ md2conf/options.py,sha256=MJka7h0ly6D5QQNXEi9ios1uQbqHQpyn07XciHV-mF8,4385
25
+ md2conf/png.py,sha256=wbo8tgm8Vxi56q5PLoTutZBU6qF73KJ6TJbs7G7LPG4,6166
26
+ md2conf/processor.py,sha256=yqRb1Njn8XWxx22byq5nrobeH9AOp55mHTVoBUJlN2A,10203
27
+ md2conf/publisher.py,sha256=6WfyZxWB59PrOro6wgkgXuFcnf7AqarlUfHo-Twzu9k,8509
28
+ md2conf/puppeteer-config.json,sha256=-dMTAN_7kNTGbDlfXzApl0KJpAWna9YKZdwMKbpOb60,159
29
+ md2conf/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
+ md2conf/scanner.py,sha256=wvh5IlD2VnAwulqY6PUe33k1D8Uag0kqTs9pQ-YFq8g,3736
31
+ md2conf/serializer.py,sha256=W4_yLJfT3vLw0PUg88lpUEnvn64CjaX3ZaKgIrwcxfw,1786
32
+ md2conf/svg.py,sha256=b98hxpVL-yFojln8NunxQRJSabMdfvazo7FkFySjALY,11054
33
+ md2conf/text.py,sha256=cnYV_JQp_v91LbQHo3qvxcEuhIdaPjCjkmLOKINcNv4,1736
34
+ md2conf/toc.py,sha256=HCtnREEucmGfqzwq-Dk6Q4ZgxW5Z8nZk6lg8UfhcoI0,2413
35
+ md2conf/uri.py,sha256=my0deyR5SlppJrYCbXF1Zz94QA1JT-HTWe9pKw7AJ_A,1158
36
+ md2conf/xml.py,sha256=uaaUDs0hfluNX74dfkY_Dxu1KmeNDGogpGRGpUVEfE4,5526
37
+ md2conf/drawio/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
+ md2conf/drawio/extension.py,sha256=-k0pAhIZXDjiKeHlTJl2MGWMYpG-PmXK91-_vBMQZnE,4389
39
+ md2conf/drawio/render.py,sha256=veSu5gjm5ggLnmaH7uvH9qNeOygBJpqhSKK_LJs0QTk,8581
40
+ md2conf/mermaid/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
+ md2conf/mermaid/config.py,sha256=5Dec2QcdB_GtnuXIW6nhJK8J5caduNZU1oz1mcmmb44,376
42
+ md2conf/mermaid/extension.py,sha256=1drXVM_KbS00dcjSCRru0wwbil4zq3aR81dHMhfe7zA,4021
43
+ md2conf/mermaid/render.py,sha256=cGq3hOemgsbh6btt7uJaRxzH4EmGis0K6_qNW5YrhIk,1834
44
+ md2conf/mermaid/scanner.py,sha256=oIpaNxiZBNcmggnjlyYGcIVOXcYQWjf1lEVdyIwE4xE,1379
45
+ md2conf/plantuml/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
+ md2conf/plantuml/config.py,sha256=j0ONhkzmAPagh00ltamTKlVEvXa6R284We9pDxRy-5U,378
47
+ md2conf/plantuml/extension.py,sha256=-WEL6Ssa3Kz_7D_AQSnB1da0bylyYZivmRQwlOBfYcM,6281
48
+ md2conf/plantuml/render.py,sha256=fwwKJIv_q1Fm9Vd8af7OcEG-5MkojZ-fxrQgA33grE8,3818
49
+ md2conf/plantuml/scanner.py,sha256=Oso6VbHVuMaPMKMazQc_bf4hhOT5WeJN5WiVPM8peyM,1347
50
+ markdown_to_confluence-0.5.3.dist-info/METADATA,sha256=7r3TveKAaJPBk14SGcJHuCXuDYD0rt7KUK6a_A8p1gE,43775
51
+ markdown_to_confluence-0.5.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
52
+ markdown_to_confluence-0.5.3.dist-info/entry_points.txt,sha256=F1zxa1wtEObtbHS-qp46330WVFLHdMnV2wQ-ZorRmX0,50
53
+ markdown_to_confluence-0.5.3.dist-info/top_level.txt,sha256=_FJfl_kHrHNidyjUOuS01ngu_jDsfc-ZjSocNRJnTzU,8
54
+ markdown_to_confluence-0.5.3.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
55
+ markdown_to_confluence-0.5.3.dist-info/RECORD,,
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2022-2025 Levente Hunyadi
3
+ Copyright (c) 2022-2026 Levente Hunyadi
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
md2conf/__init__.py CHANGED
@@ -5,9 +5,9 @@ Parses Markdown files, converts Markdown content into the Confluence Storage For
5
5
  Confluence API endpoints to upload images and content.
6
6
  """
7
7
 
8
- __version__ = "0.5.1"
8
+ __version__ = "0.5.3"
9
9
  __author__ = "Levente Hunyadi"
10
- __copyright__ = "Copyright 2022-2025, Levente Hunyadi"
10
+ __copyright__ = "Copyright 2022-2026, Levente Hunyadi"
11
11
  __license__ = "MIT"
12
12
  __maintainer__ = "Levente Hunyadi"
13
13
  __status__ = "Production"
md2conf/__main__.py CHANGED
@@ -4,7 +4,7 @@ Publish Markdown files to Confluence wiki.
4
4
  Parses Markdown files, converts Markdown content into the Confluence Storage Format (XHTML), and invokes
5
5
  Confluence API endpoints to upload images and content.
6
6
 
7
- Copyright 2022-2025, Levente Hunyadi
7
+ Copyright 2022-2026, Levente Hunyadi
8
8
 
9
9
  :see: https://github.com/hunyadi/md2conf
10
10
  """
@@ -19,10 +19,10 @@ from pathlib import Path
19
19
  from typing import Any, Iterable, Literal, Sequence
20
20
 
21
21
  from . import __version__
22
- from .domain import ConfluenceDocumentOptions, ConfluencePageID
23
- from .environment import ArgumentError, ConfluenceConnectionProperties, ConfluenceSiteProperties
24
- from .extra import override
22
+ from .compatibility import override
23
+ from .environment import ArgumentError, ConfluenceSiteProperties, ConnectionProperties
25
24
  from .metadata import ConfluenceSiteMetadata
25
+ from .options import ConfluencePageID, ConverterOptions, DocumentOptions, ImageLayoutOptions, LayoutOptions
26
26
 
27
27
 
28
28
  class Arguments(argparse.Namespace):
@@ -34,19 +34,24 @@ class Arguments(argparse.Namespace):
34
34
  api_key: str | None
35
35
  space: str | None
36
36
  loglevel: str
37
- ignore_invalid_url: bool
38
37
  heading_anchors: bool
38
+ ignore_invalid_url: bool
39
39
  root_page: str | None
40
40
  keep_hierarchy: bool
41
+ skip_title_heading: bool
42
+ title_prefix: str | None
41
43
  generated_by: str | None
44
+ prefer_raster: bool
42
45
  render_drawio: bool
43
46
  render_mermaid: bool
47
+ render_plantuml: bool
44
48
  render_latex: bool
45
49
  diagram_output_format: Literal["png", "svg"]
46
50
  local: bool
47
51
  headers: dict[str, str]
48
52
  webui_links: bool
49
53
  alignment: Literal["center", "left", "right"]
54
+ max_image_width: int | None
50
55
  use_panel: bool
51
56
 
52
57
 
@@ -151,6 +156,7 @@ def get_parser() -> argparse.ArgumentParser:
151
156
  parser.add_argument(
152
157
  "--generated-by",
153
158
  default="This page has been generated with a tool.",
159
+ metavar="MARKDOWN",
154
160
  help="Add prompt to pages (default: 'This page has been generated with a tool.').",
155
161
  )
156
162
  parser.add_argument(
@@ -186,6 +192,19 @@ def get_parser() -> argparse.ArgumentParser:
186
192
  action="store_false",
187
193
  help="Upload Mermaid diagram sources as Confluence page attachments. (Marketplace app required to display.)",
188
194
  )
195
+ parser.add_argument(
196
+ "--render-plantuml",
197
+ dest="render_plantuml",
198
+ action="store_true",
199
+ default=True,
200
+ help="Render PlantUML diagrams as image files. (Installed utility required to convert.)",
201
+ )
202
+ parser.add_argument(
203
+ "--no-render-plantuml",
204
+ dest="render_plantuml",
205
+ action="store_false",
206
+ help="Upload PlantUML diagram sources as Confluence page attachments. (Marketplace app required to display.)",
207
+ )
189
208
  parser.add_argument(
190
209
  "--render-latex",
191
210
  dest="render_latex",
@@ -206,6 +225,19 @@ def get_parser() -> argparse.ArgumentParser:
206
225
  default="png",
207
226
  help="Format for rendering Mermaid and draw.io diagrams (default: 'png').",
208
227
  )
228
+ parser.add_argument(
229
+ "--prefer-raster",
230
+ dest="prefer_raster",
231
+ action="store_true",
232
+ default=True,
233
+ help="Prefer PNG over SVG when both exist (default: enabled).",
234
+ )
235
+ parser.add_argument(
236
+ "--no-prefer-raster",
237
+ dest="prefer_raster",
238
+ action="store_false",
239
+ help="Use SVG files directly instead of preferring PNG equivalents.",
240
+ )
209
241
  parser.add_argument(
210
242
  "--heading-anchors",
211
243
  action="store_true",
@@ -225,18 +257,22 @@ def get_parser() -> argparse.ArgumentParser:
225
257
  help="Emit a warning but otherwise ignore relative URLs that point to ill-specified locations.",
226
258
  )
227
259
  parser.add_argument(
228
- "--local",
260
+ "--skip-title-heading",
229
261
  action="store_true",
230
262
  default=False,
231
- help="Write XHTML-based Confluence Storage Format files locally without invoking Confluence API.",
263
+ help="Skip the first heading from document body when it is used as the page title (does not apply if title comes from front-matter).",
232
264
  )
233
265
  parser.add_argument(
234
- "--headers",
235
- nargs="+",
236
- required=False,
237
- action=KwargsAppendAction,
238
- metavar="KEY=VALUE",
239
- help="Apply custom headers to all Confluence API requests.",
266
+ "--no-skip-title-heading",
267
+ dest="skip_title_heading",
268
+ action="store_false",
269
+ help="Keep the first heading in document body even when used as page title (default).",
270
+ )
271
+ parser.add_argument(
272
+ "--title-prefix",
273
+ default=None,
274
+ metavar="TEXT",
275
+ help="String to prepend to Confluence page title for each published page.",
240
276
  )
241
277
  parser.add_argument(
242
278
  "--webui-links",
@@ -251,12 +287,33 @@ def get_parser() -> argparse.ArgumentParser:
251
287
  default="center",
252
288
  help="Alignment for block-level images and formulas (default: 'center').",
253
289
  )
290
+ parser.add_argument(
291
+ "--max-image-width",
292
+ dest="max_image_width",
293
+ type=int,
294
+ default=None,
295
+ help="Maximum display width for images [px]. Wider images are scaled down for page display. Original size kept for full-size viewing.",
296
+ )
254
297
  parser.add_argument(
255
298
  "--use-panel",
256
299
  action="store_true",
257
300
  default=False,
258
301
  help="Transform admonitions and alerts into a Confluence custom panel.",
259
302
  )
303
+ parser.add_argument(
304
+ "--local",
305
+ action="store_true",
306
+ default=False,
307
+ help="Write XHTML-based Confluence Storage Format files locally without invoking Confluence API.",
308
+ )
309
+ parser.add_argument(
310
+ "--headers",
311
+ nargs="+",
312
+ required=False,
313
+ action=KwargsAppendAction,
314
+ metavar="KEY=VALUE",
315
+ help="Apply custom headers to all Confluence API requests.",
316
+ )
260
317
  return parser
261
318
 
262
319
 
@@ -279,19 +336,30 @@ def main() -> None:
279
336
  format="%(asctime)s - %(levelname)s - %(funcName)s [%(lineno)d] - %(message)s",
280
337
  )
281
338
 
282
- options = ConfluenceDocumentOptions(
283
- heading_anchors=args.heading_anchors,
284
- ignore_invalid_url=args.ignore_invalid_url,
285
- generated_by=args.generated_by,
339
+ options = DocumentOptions(
286
340
  root_page_id=ConfluencePageID(args.root_page) if args.root_page else None,
287
341
  keep_hierarchy=args.keep_hierarchy,
288
- render_drawio=args.render_drawio,
289
- render_mermaid=args.render_mermaid,
290
- render_latex=args.render_latex,
291
- diagram_output_format=args.diagram_output_format,
292
- webui_links=args.webui_links,
293
- alignment=args.alignment,
294
- use_panel=args.use_panel,
342
+ title_prefix=args.title_prefix,
343
+ generated_by=args.generated_by,
344
+ converter=ConverterOptions(
345
+ heading_anchors=args.heading_anchors,
346
+ ignore_invalid_url=args.ignore_invalid_url,
347
+ skip_title_heading=args.skip_title_heading,
348
+ prefer_raster=args.prefer_raster,
349
+ render_drawio=args.render_drawio,
350
+ render_mermaid=args.render_mermaid,
351
+ render_plantuml=args.render_plantuml,
352
+ render_latex=args.render_latex,
353
+ diagram_output_format=args.diagram_output_format,
354
+ webui_links=args.webui_links,
355
+ use_panel=args.use_panel,
356
+ layout=LayoutOptions(
357
+ image=ImageLayoutOptions(
358
+ alignment=args.alignment,
359
+ max_width=args.max_image_width,
360
+ ),
361
+ ),
362
+ ),
295
363
  )
296
364
  if args.local:
297
365
  from .local import LocalConverter
@@ -317,7 +385,7 @@ def main() -> None:
317
385
  from .publisher import Publisher
318
386
 
319
387
  try:
320
- properties = ConfluenceConnectionProperties(
388
+ properties = ConnectionProperties(
321
389
  api_url=args.api_url,
322
390
  domain=args.domain,
323
391
  base_path=args.path,
@@ -330,10 +398,7 @@ def main() -> None:
330
398
  parser.error(str(e))
331
399
  try:
332
400
  with ConfluenceAPI(properties) as api:
333
- Publisher(
334
- api,
335
- options,
336
- ).process(args.mdpath)
401
+ Publisher(api, options).process(args.mdpath)
337
402
  except HTTPError as err:
338
403
  logging.error(err)
339
404