markdown-to-confluence 0.3.4__py3-none-any.whl → 0.4.0__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.4.dist-info → markdown_to_confluence-0.4.0.dist-info}/METADATA +131 -14
- markdown_to_confluence-0.4.0.dist-info/RECORD +25 -0
- {markdown_to_confluence-0.3.4.dist-info → markdown_to_confluence-0.4.0.dist-info}/WHEEL +1 -1
- md2conf/__init__.py +1 -1
- md2conf/__main__.py +18 -7
- md2conf/api.py +492 -187
- md2conf/application.py +100 -83
- md2conf/collection.py +31 -0
- md2conf/converter.py +51 -112
- md2conf/emoji.py +28 -3
- md2conf/extra.py +14 -0
- md2conf/local.py +33 -45
- md2conf/matcher.py +54 -13
- md2conf/mermaid.py +10 -4
- md2conf/metadata.py +1 -3
- md2conf/processor.py +137 -43
- md2conf/properties.py +24 -5
- md2conf/scanner.py +149 -0
- markdown_to_confluence-0.3.4.dist-info/RECORD +0 -22
- {markdown_to_confluence-0.3.4.dist-info → markdown_to_confluence-0.4.0.dist-info}/entry_points.txt +0 -0
- {markdown_to_confluence-0.3.4.dist-info → markdown_to_confluence-0.4.0.dist-info}/licenses/LICENSE +0 -0
- {markdown_to_confluence-0.3.4.dist-info → markdown_to_confluence-0.4.0.dist-info}/top_level.txt +0 -0
- {markdown_to_confluence-0.3.4.dist-info → markdown_to_confluence-0.4.0.dist-info}/zip-safe +0 -0
md2conf/scanner.py
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
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, TypeVar
|
|
13
|
+
|
|
14
|
+
import yaml
|
|
15
|
+
from strong_typing.core import JsonType
|
|
16
|
+
from strong_typing.serialization import DeserializerOptions, json_to_object
|
|
17
|
+
|
|
18
|
+
T = TypeVar("T")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _json_to_object(
|
|
22
|
+
typ: type[T],
|
|
23
|
+
data: JsonType,
|
|
24
|
+
) -> T:
|
|
25
|
+
return json_to_object(typ, data, options=DeserializerOptions(skip_unassigned=True))
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def extract_value(pattern: str, text: str) -> tuple[Optional[str], str]:
|
|
29
|
+
values: list[str] = []
|
|
30
|
+
|
|
31
|
+
def _repl_func(matchobj: re.Match[str]) -> str:
|
|
32
|
+
values.append(matchobj.group(1))
|
|
33
|
+
return ""
|
|
34
|
+
|
|
35
|
+
text = re.sub(pattern, _repl_func, text, count=1, flags=re.ASCII)
|
|
36
|
+
value = values[0] if values else None
|
|
37
|
+
return value, text
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def extract_frontmatter_block(text: str) -> tuple[Optional[str], str]:
|
|
41
|
+
"Extracts the front-matter from a Markdown document as a blob of unparsed text."
|
|
42
|
+
|
|
43
|
+
return extract_value(r"(?ms)\A---$(.+?)^---$", text)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def extract_frontmatter_properties(text: str) -> tuple[Optional[dict[str, Any]], str]:
|
|
47
|
+
"Extracts the front-matter from a Markdown document as a dictionary."
|
|
48
|
+
|
|
49
|
+
block, text = extract_frontmatter_block(text)
|
|
50
|
+
|
|
51
|
+
properties: Optional[dict[str, Any]] = None
|
|
52
|
+
if block is not None:
|
|
53
|
+
data = yaml.safe_load(block)
|
|
54
|
+
if isinstance(data, dict):
|
|
55
|
+
properties = data
|
|
56
|
+
|
|
57
|
+
return properties, text
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@dataclass
|
|
61
|
+
class DocumentProperties:
|
|
62
|
+
"""
|
|
63
|
+
An object that holds properties extracted from the front-matter of a Markdown document.
|
|
64
|
+
|
|
65
|
+
:param page_id: Confluence page ID.
|
|
66
|
+
:param space_key: Confluence space key.
|
|
67
|
+
:param confluence_page_id: Confluence page ID. (Alternative name for JSON de-serialization.)
|
|
68
|
+
:param confluence_space_key: Confluence space key. (Alternative name for JSON de-serialization.)
|
|
69
|
+
:param generated_by: Text identifying the tool that generated the document.
|
|
70
|
+
:param title: The title extracted from front-matter.
|
|
71
|
+
:param tags: A list of tags (content labels) extracted from front-matter.
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
page_id: Optional[str]
|
|
75
|
+
space_key: Optional[str]
|
|
76
|
+
confluence_page_id: Optional[str]
|
|
77
|
+
confluence_space_key: Optional[str]
|
|
78
|
+
generated_by: Optional[str]
|
|
79
|
+
title: Optional[str]
|
|
80
|
+
tags: Optional[list[str]]
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
@dataclass
|
|
84
|
+
class ScannedDocument:
|
|
85
|
+
"""
|
|
86
|
+
An object that holds properties extracted from a Markdown document, including remaining source text.
|
|
87
|
+
|
|
88
|
+
:param page_id: Confluence page ID.
|
|
89
|
+
:param space_key: Confluence space key.
|
|
90
|
+
:param generated_by: Text identifying the tool that generated the document.
|
|
91
|
+
:param title: The title extracted from front-matter.
|
|
92
|
+
:param tags: A list of tags (content labels) extracted from front-matter.
|
|
93
|
+
:param text: Text that remains after front-matter and inline properties have been extracted.
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
page_id: Optional[str]
|
|
97
|
+
space_key: Optional[str]
|
|
98
|
+
generated_by: Optional[str]
|
|
99
|
+
title: Optional[str]
|
|
100
|
+
tags: Optional[list[str]]
|
|
101
|
+
text: str
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class Scanner:
|
|
105
|
+
def read(self, absolute_path: Path) -> ScannedDocument:
|
|
106
|
+
"""
|
|
107
|
+
Extracts essential properties from a Markdown document.
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
# parse file
|
|
111
|
+
with open(absolute_path, "r", encoding="utf-8") as f:
|
|
112
|
+
text = f.read()
|
|
113
|
+
|
|
114
|
+
# extract Confluence page ID
|
|
115
|
+
page_id, text = extract_value(
|
|
116
|
+
r"<!--\s+confluence[-_]page[-_]id:\s*(\d+)\s+-->", text
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# extract Confluence space key
|
|
120
|
+
space_key, text = extract_value(
|
|
121
|
+
r"<!--\s+confluence[-_]space[-_]key:\s*(\S+)\s+-->", text
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
# extract 'generated-by' tag text
|
|
125
|
+
generated_by, text = extract_value(
|
|
126
|
+
r"<!--\s+generated[-_]by:\s*(.*)\s+-->", text
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
title: Optional[str] = None
|
|
130
|
+
tags: Optional[list[str]] = None
|
|
131
|
+
|
|
132
|
+
# extract front-matter
|
|
133
|
+
data, text = extract_frontmatter_properties(text)
|
|
134
|
+
if data is not None:
|
|
135
|
+
p = _json_to_object(DocumentProperties, data)
|
|
136
|
+
page_id = page_id or p.confluence_page_id or p.page_id
|
|
137
|
+
space_key = space_key or p.confluence_space_key or p.space_key
|
|
138
|
+
generated_by = generated_by or p.generated_by
|
|
139
|
+
title = p.title
|
|
140
|
+
tags = p.tags
|
|
141
|
+
|
|
142
|
+
return ScannedDocument(
|
|
143
|
+
page_id=page_id,
|
|
144
|
+
space_key=space_key,
|
|
145
|
+
generated_by=generated_by,
|
|
146
|
+
title=title,
|
|
147
|
+
tags=tags,
|
|
148
|
+
text=text,
|
|
149
|
+
)
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
markdown_to_confluence-0.3.4.dist-info/licenses/LICENSE,sha256=Pv43so2bPfmKhmsrmXFyAvS7M30-1i1tzjz6-dfhyOo,1077
|
|
2
|
-
md2conf/__init__.py,sha256=9gI6OYCv9-54FzxjNHLOH09H5quUDEMWq9pdbhnwoXM,402
|
|
3
|
-
md2conf/__main__.py,sha256=bFcfmSnTWeuhmDm7bJ3jJabZ2S8W9biuAP6_R-Cc9As,8034
|
|
4
|
-
md2conf/api.py,sha256=ZIYoBXclLbzrrQ_oFRllsTEnQIMbxqd9OD80-AC5qM0,22769
|
|
5
|
-
md2conf/application.py,sha256=eIVeAGUzfdIq1uYLYpTg30UNSq-YcUIY-OgKKK3M4E4,6436
|
|
6
|
-
md2conf/converter.py,sha256=2Sgq1WQd-dCtrdTVrBwhowPC8PmubMNCH1aAcRwntjs,39404
|
|
7
|
-
md2conf/emoji.py,sha256=48QJtOD0F3Be1laYLvAOwe0GxrJS-vcfjtCdiBsNcAc,1960
|
|
8
|
-
md2conf/entities.dtd,sha256=M6NzqL5N7dPs_eUA_6sDsiSLzDaAacrx9LdttiufvYU,30215
|
|
9
|
-
md2conf/local.py,sha256=AOuwyvPOXrRRPGOTDeoVYkMPJ9MI2zqRGAvHuY35wy4,3884
|
|
10
|
-
md2conf/matcher.py,sha256=FgMFPvGiOqGezCs8OyerfsVo-iIHFoI6LRMzdcjM5UY,3693
|
|
11
|
-
md2conf/mermaid.py,sha256=un_KHBDpG5Zad_QD3HN1uBwUxp4I-HVJYhNKbH7KwcA,2312
|
|
12
|
-
md2conf/metadata.py,sha256=9BtNRsICbKzPTs63P70XekNARePdW1DtdKNJqXh2ZFM,1013
|
|
13
|
-
md2conf/processor.py,sha256=Ko_3WqLK6jM-bEN7OD9Vc3g3vhSjRYawz3fG6uoUsXc,6733
|
|
14
|
-
md2conf/properties.py,sha256=TOCXLdTfYkKjRwZaMgvXw0mNCI4opEUwpBXro2Kv2B4,2467
|
|
15
|
-
md2conf/puppeteer-config.json,sha256=-dMTAN_7kNTGbDlfXzApl0KJpAWna9YKZdwMKbpOb60,159
|
|
16
|
-
md2conf/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
|
-
markdown_to_confluence-0.3.4.dist-info/METADATA,sha256=PUtJXudDooVfwOzVtohxweWHMjgDv5CIrDvyqiJ0tlg,17745
|
|
18
|
-
markdown_to_confluence-0.3.4.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
|
19
|
-
markdown_to_confluence-0.3.4.dist-info/entry_points.txt,sha256=F1zxa1wtEObtbHS-qp46330WVFLHdMnV2wQ-ZorRmX0,50
|
|
20
|
-
markdown_to_confluence-0.3.4.dist-info/top_level.txt,sha256=_FJfl_kHrHNidyjUOuS01ngu_jDsfc-ZjSocNRJnTzU,8
|
|
21
|
-
markdown_to_confluence-0.3.4.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
|
22
|
-
markdown_to_confluence-0.3.4.dist-info/RECORD,,
|
{markdown_to_confluence-0.3.4.dist-info → markdown_to_confluence-0.4.0.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{markdown_to_confluence-0.3.4.dist-info → markdown_to_confluence-0.4.0.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{markdown_to_confluence-0.3.4.dist-info → markdown_to_confluence-0.4.0.dist-info}/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|