markdown-to-confluence 0.3.3__py3-none-any.whl → 0.3.5__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.
- {markdown_to_confluence-0.3.3.dist-info → markdown_to_confluence-0.3.5.dist-info}/METADATA +24 -11
- markdown_to_confluence-0.3.5.dist-info/RECORD +23 -0
- {markdown_to_confluence-0.3.3.dist-info → markdown_to_confluence-0.3.5.dist-info}/WHEEL +1 -1
- md2conf/__init__.py +1 -1
- md2conf/__main__.py +6 -5
- md2conf/api.py +235 -45
- md2conf/application.py +100 -182
- md2conf/converter.py +53 -112
- md2conf/local.py +125 -0
- md2conf/matcher.py +54 -13
- md2conf/mermaid.py +10 -4
- md2conf/metadata.py +42 -0
- md2conf/processor.py +158 -90
- md2conf/scanner.py +117 -0
- markdown_to_confluence-0.3.3.dist-info/RECORD +0 -20
- {markdown_to_confluence-0.3.3.dist-info → markdown_to_confluence-0.3.5.dist-info}/entry_points.txt +0 -0
- {markdown_to_confluence-0.3.3.dist-info → markdown_to_confluence-0.3.5.dist-info}/licenses/LICENSE +0 -0
- {markdown_to_confluence-0.3.3.dist-info → markdown_to_confluence-0.3.5.dist-info}/top_level.txt +0 -0
- {markdown_to_confluence-0.3.3.dist-info → markdown_to_confluence-0.3.5.dist-info}/zip-safe +0 -0
md2conf/scanner.py
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Publish Markdown files to Confluence wiki.
|
|
3
|
+
|
|
4
|
+
Copyright 2022-2025, Levente Hunyadi
|
|
5
|
+
|
|
6
|
+
:see: https://github.com/hunyadi/md2conf
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import re
|
|
10
|
+
from dataclasses import dataclass
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Any, Optional
|
|
13
|
+
|
|
14
|
+
import yaml
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def extract_value(pattern: str, text: str) -> tuple[Optional[str], str]:
|
|
18
|
+
values: list[str] = []
|
|
19
|
+
|
|
20
|
+
def _repl_func(matchobj: re.Match) -> str:
|
|
21
|
+
values.append(matchobj.group(1))
|
|
22
|
+
return ""
|
|
23
|
+
|
|
24
|
+
text = re.sub(pattern, _repl_func, text, count=1, flags=re.ASCII)
|
|
25
|
+
value = values[0] if values else None
|
|
26
|
+
return value, text
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def extract_frontmatter_block(text: str) -> tuple[Optional[str], str]:
|
|
30
|
+
"Extracts the front-matter from a Markdown document as a blob of unparsed text."
|
|
31
|
+
|
|
32
|
+
return extract_value(r"(?ms)\A---$(.+?)^---$", text)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def extract_frontmatter_properties(text: str) -> tuple[Optional[dict[str, Any]], str]:
|
|
36
|
+
"Extracts the front-matter from a Markdown document as a dictionary."
|
|
37
|
+
|
|
38
|
+
block, text = extract_frontmatter_block(text)
|
|
39
|
+
|
|
40
|
+
properties: Optional[dict[str, Any]] = None
|
|
41
|
+
if block is not None:
|
|
42
|
+
data = yaml.safe_load(block)
|
|
43
|
+
if isinstance(data, dict):
|
|
44
|
+
properties = data
|
|
45
|
+
|
|
46
|
+
return properties, text
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def get_string(properties: dict[str, Any], key: str) -> Optional[str]:
|
|
50
|
+
value = properties.get(key)
|
|
51
|
+
if value is None:
|
|
52
|
+
return None
|
|
53
|
+
elif not isinstance(value, str):
|
|
54
|
+
raise ValueError(
|
|
55
|
+
f"expected dictionary value type of `str` for key `{key}`; got value of type `{type(value).__name__}`"
|
|
56
|
+
)
|
|
57
|
+
else:
|
|
58
|
+
return value
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@dataclass
|
|
62
|
+
class ScannedDocument:
|
|
63
|
+
"""
|
|
64
|
+
An object that holds properties extracted from a Markdown document, including remaining source text.
|
|
65
|
+
|
|
66
|
+
:param page_id: Confluence page ID.
|
|
67
|
+
:param space_key: Confluence space key.
|
|
68
|
+
:param generated_by: Text identifying the tool that generated the document.
|
|
69
|
+
:param title: The title extracted from front-matter.
|
|
70
|
+
:param text: Text that remains after front-matter and inline properties have been extracted.
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
page_id: Optional[str]
|
|
74
|
+
space_key: Optional[str]
|
|
75
|
+
generated_by: Optional[str]
|
|
76
|
+
title: Optional[str]
|
|
77
|
+
text: str
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class Scanner:
|
|
81
|
+
def read(self, absolute_path: Path) -> ScannedDocument:
|
|
82
|
+
"""
|
|
83
|
+
Extracts essential properties from a Markdown document.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
# parse file
|
|
87
|
+
with open(absolute_path, "r", encoding="utf-8") as f:
|
|
88
|
+
text = f.read()
|
|
89
|
+
|
|
90
|
+
# extract Confluence page ID
|
|
91
|
+
page_id, text = extract_value(r"<!--\s+confluence-page-id:\s*(\d+)\s+-->", text)
|
|
92
|
+
|
|
93
|
+
# extract Confluence space key
|
|
94
|
+
space_key, text = extract_value(
|
|
95
|
+
r"<!--\s+confluence-space-key:\s*(\S+)\s+-->", text
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
# extract 'generated-by' tag text
|
|
99
|
+
generated_by, text = extract_value(r"<!--\s+generated-by:\s*(.*)\s+-->", text)
|
|
100
|
+
|
|
101
|
+
title: Optional[str] = None
|
|
102
|
+
|
|
103
|
+
# extract front-matter
|
|
104
|
+
properties, text = extract_frontmatter_properties(text)
|
|
105
|
+
if properties is not None:
|
|
106
|
+
page_id = page_id or get_string(properties, "confluence-page-id")
|
|
107
|
+
space_key = space_key or get_string(properties, "confluence-space-key")
|
|
108
|
+
generated_by = generated_by or get_string(properties, "generated-by")
|
|
109
|
+
title = get_string(properties, "title")
|
|
110
|
+
|
|
111
|
+
return ScannedDocument(
|
|
112
|
+
page_id=page_id,
|
|
113
|
+
space_key=space_key,
|
|
114
|
+
generated_by=generated_by,
|
|
115
|
+
title=title,
|
|
116
|
+
text=text,
|
|
117
|
+
)
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
markdown_to_confluence-0.3.3.dist-info/licenses/LICENSE,sha256=Pv43so2bPfmKhmsrmXFyAvS7M30-1i1tzjz6-dfhyOo,1077
|
|
2
|
-
md2conf/__init__.py,sha256=NHoSu8tHMVLytWmla4BA_Uzkl-04rV_O8YkkFxUkT_E,402
|
|
3
|
-
md2conf/__main__.py,sha256=aTRiXcvoIYMkwCGejL6MUriHXBo3qVP2Acr2I-XzMyg,7947
|
|
4
|
-
md2conf/api.py,sha256=S5IB7j48wE9MHSj1jodHYmTE6scSXb80faULW6-5RjU,20376
|
|
5
|
-
md2conf/application.py,sha256=FkJ9zYBLwYcCRkd_WiX6JI6nlw4QMETmrOXHeSzCwCE,9735
|
|
6
|
-
md2conf/converter.py,sha256=B4Z8afTmhea6nSXhzDVxN55GfMvlY34tGqCLspQ_p5g,38983
|
|
7
|
-
md2conf/emoji.py,sha256=48QJtOD0F3Be1laYLvAOwe0GxrJS-vcfjtCdiBsNcAc,1960
|
|
8
|
-
md2conf/entities.dtd,sha256=M6NzqL5N7dPs_eUA_6sDsiSLzDaAacrx9LdttiufvYU,30215
|
|
9
|
-
md2conf/matcher.py,sha256=FgMFPvGiOqGezCs8OyerfsVo-iIHFoI6LRMzdcjM5UY,3693
|
|
10
|
-
md2conf/mermaid.py,sha256=un_KHBDpG5Zad_QD3HN1uBwUxp4I-HVJYhNKbH7KwcA,2312
|
|
11
|
-
md2conf/processor.py,sha256=9jPswgPewh2glLSHdgxyXesGxkcxPVa_h7oUhM9EsA4,4740
|
|
12
|
-
md2conf/properties.py,sha256=TOCXLdTfYkKjRwZaMgvXw0mNCI4opEUwpBXro2Kv2B4,2467
|
|
13
|
-
md2conf/puppeteer-config.json,sha256=-dMTAN_7kNTGbDlfXzApl0KJpAWna9YKZdwMKbpOb60,159
|
|
14
|
-
md2conf/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
-
markdown_to_confluence-0.3.3.dist-info/METADATA,sha256=SiOfBvA3jMCn3Hjd_Let9R-DqcMuPG48xP-1x2pg_JI,16495
|
|
16
|
-
markdown_to_confluence-0.3.3.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
|
|
17
|
-
markdown_to_confluence-0.3.3.dist-info/entry_points.txt,sha256=F1zxa1wtEObtbHS-qp46330WVFLHdMnV2wQ-ZorRmX0,50
|
|
18
|
-
markdown_to_confluence-0.3.3.dist-info/top_level.txt,sha256=_FJfl_kHrHNidyjUOuS01ngu_jDsfc-ZjSocNRJnTzU,8
|
|
19
|
-
markdown_to_confluence-0.3.3.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
20
|
-
markdown_to_confluence-0.3.3.dist-info/RECORD,,
|
{markdown_to_confluence-0.3.3.dist-info → markdown_to_confluence-0.3.5.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{markdown_to_confluence-0.3.3.dist-info → markdown_to_confluence-0.3.5.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{markdown_to_confluence-0.3.3.dist-info → markdown_to_confluence-0.3.5.dist-info}/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|