mkdocs2confluence 0.7.7__tar.gz → 0.7.9__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.7.7/src/mkdocs2confluence.egg-info → mkdocs2confluence-0.7.9}/PKG-INFO +1 -1
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/pyproject.toml +1 -1
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9/src/mkdocs2confluence.egg-info}/PKG-INFO +1 -1
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/emitter/xhtml.py +5 -1
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/ir/nodes.py +2 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/parser/markdown.py +4 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/preprocess/icons.py +102 -107
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/tests/test_emitter.py +12 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/tests/test_icons.py +43 -46
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/tests/test_parser.py +15 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/LICENSE +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/README.md +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/setup.cfg +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs2confluence.egg-info/SOURCES.txt +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs2confluence.egg-info/dependency_links.txt +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs2confluence.egg-info/entry_points.txt +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs2confluence.egg-info/requires.txt +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs2confluence.egg-info/top_level.txt +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/__init__.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/cli.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/emitter/__init__.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/ir/__init__.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/ir/document.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/ir/treeutil.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/loader/__init__.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/loader/config.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/loader/extra_css.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/loader/nav.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/loader/page.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/parser/__init__.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/pdf/__init__.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/pdf/generator.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/pdf/render.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/preprocess/__init__.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/preprocess/abbrevs.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/preprocess/fence.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/preprocess/frontmatter.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/preprocess/includes.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/preprocess/linkdefs.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/preview/__init__.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/preview/render.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/preview/server.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/publisher/__init__.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/publisher/client.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/publisher/pipeline.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/transforms/__init__.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/transforms/abbrevs.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/transforms/assets.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/transforms/editlink.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/transforms/images.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/transforms/internallinks.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/transforms/mermaid.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/tests/test_abbrevs.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/tests/test_cli.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/tests/test_editlink.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/tests/test_extra_css.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/tests/test_frontmatter.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/tests/test_images.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/tests/test_internallinks.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/tests/test_ir.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/tests/test_linkdefs.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/tests/test_loader.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/tests/test_mermaid.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/tests/test_page_loader.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/tests/test_pdf.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/tests/test_preprocess.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/tests/test_preview.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/tests/test_publish_client.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/tests/test_publish_config.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/tests/test_publish_pipeline.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/tests/test_server.py +0 -0
- {mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/tests/test_treeutil.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "mkdocs2confluence"
|
|
3
|
-
version = "0.7.
|
|
3
|
+
version = "0.7.9"
|
|
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.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/emitter/xhtml.py
RENAMED
|
@@ -307,7 +307,9 @@ def _emit_admonition(node: Admonition) -> str:
|
|
|
307
307
|
body = emit(node.children)
|
|
308
308
|
|
|
309
309
|
# ??? and ???+ → Confluence expand macro (collapsible)
|
|
310
|
-
|
|
310
|
+
# ???+ means "expanded by default" — Confluence expand has no such option,
|
|
311
|
+
# so degrade to a regular admonition macro (always visible).
|
|
312
|
+
if node.collapsible and not node.expanded:
|
|
311
313
|
return (
|
|
312
314
|
'<ac:structured-macro ac:name="expand">\n'
|
|
313
315
|
f' <ac:parameter ac:name="title">{html.escape(title)}</ac:parameter>\n'
|
|
@@ -315,6 +317,8 @@ def _emit_admonition(node: Admonition) -> str:
|
|
|
315
317
|
"</ac:structured-macro>\n"
|
|
316
318
|
)
|
|
317
319
|
|
|
320
|
+
# Fall through for ???+ (expanded=True) — render as a regular admonition below.
|
|
321
|
+
|
|
318
322
|
if node.kind in _ADMONITION_DANGER_KINDS:
|
|
319
323
|
colours = "".join(
|
|
320
324
|
f' <ac:parameter ac:name="{k}">{v}</ac:parameter>\n'
|
|
@@ -338,12 +338,14 @@ class Admonition(IRNode):
|
|
|
338
338
|
children: Block nodes that form the admonition body.
|
|
339
339
|
collapsible: ``True`` when opened with ``???`` (collapsed by default)
|
|
340
340
|
or ``???+`` (expanded by default).
|
|
341
|
+
expanded: ``True`` only for ``???+`` — expanded by default.
|
|
341
342
|
"""
|
|
342
343
|
|
|
343
344
|
kind: str
|
|
344
345
|
title: str | None
|
|
345
346
|
children: tuple[IRNode, ...]
|
|
346
347
|
collapsible: bool = False
|
|
348
|
+
expanded: bool = False
|
|
347
349
|
|
|
348
350
|
|
|
349
351
|
@dataclass(frozen=True)
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/parser/markdown.py
RENAMED
|
@@ -139,6 +139,7 @@ class _AdmonitionToken:
|
|
|
139
139
|
kind: str
|
|
140
140
|
title: str | None # None → use the kind's default Confluence title
|
|
141
141
|
collapsible: bool # True for ??? and ???+
|
|
142
|
+
expanded: bool # True for ???+ (expanded by default)
|
|
142
143
|
body_tokens: list[_Token]
|
|
143
144
|
|
|
144
145
|
|
|
@@ -386,6 +387,7 @@ def _tokenize(text: str) -> list[_Token]:
|
|
|
386
387
|
kind = adm_m.group("kind")
|
|
387
388
|
title = adm_m.group("title") # None if no quoted title given
|
|
388
389
|
collapsible = marker.startswith("?")
|
|
390
|
+
expanded = marker == "???+"
|
|
389
391
|
i += 1
|
|
390
392
|
# Collect body: blank lines or lines indented by ≥4 spaces / 1 tab.
|
|
391
393
|
body_raw: list[str] = []
|
|
@@ -408,6 +410,7 @@ def _tokenize(text: str) -> list[_Token]:
|
|
|
408
410
|
kind=kind,
|
|
409
411
|
title=title,
|
|
410
412
|
collapsible=collapsible,
|
|
413
|
+
expanded=expanded,
|
|
411
414
|
body_tokens=body_tokens,
|
|
412
415
|
)
|
|
413
416
|
)
|
|
@@ -1055,6 +1058,7 @@ def _build_tree(
|
|
|
1055
1058
|
kind=token.kind,
|
|
1056
1059
|
title=token.title,
|
|
1057
1060
|
collapsible=token.collapsible,
|
|
1061
|
+
expanded=token.expanded,
|
|
1058
1062
|
children=body_nodes,
|
|
1059
1063
|
),
|
|
1060
1064
|
stack,
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/preprocess/icons.py
RENAMED
|
@@ -1,18 +1,16 @@
|
|
|
1
1
|
"""Icon shortcode preprocessing.
|
|
2
2
|
|
|
3
3
|
Replaces MkDocs Material / FontAwesome / Octicons / Simple icon shortcodes
|
|
4
|
-
(e.g. ``:material-check-circle:``) with the closest Unicode
|
|
4
|
+
(e.g. ``:material-check-circle:``) with the closest Unicode emoji equivalent,
|
|
5
5
|
or strips them silently when no mapping is found.
|
|
6
6
|
|
|
7
7
|
Strategy: split the icon name on ``-`` and test each part against a small
|
|
8
8
|
keyword→symbol table. The first matching keyword wins. This keeps the
|
|
9
9
|
mapping set tiny and maintainable without requiring a full icon inventory.
|
|
10
10
|
|
|
11
|
-
**
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
deployments that use MySQL ``utf8`` (not ``utf8mb4``) and render as ``???``.
|
|
15
|
-
Where no good BMP symbol exists the shortcode is stripped silently (``""``).
|
|
11
|
+
**Unicode range**: Confluence Cloud stores pages as UTF-8 with full Unicode
|
|
12
|
+
support (utf8mb4), so supplementary-plane emoji (U+10000+) are safe.
|
|
13
|
+
Symbols without a clear emoji equivalent are still stripped silently (``""``).
|
|
16
14
|
"""
|
|
17
15
|
|
|
18
16
|
from __future__ import annotations
|
|
@@ -29,60 +27,57 @@ _ICON_RE = re.compile(
|
|
|
29
27
|
# Must not overlap with _ICON_RE (those all contain a hyphenated prefix).
|
|
30
28
|
_STANDARD_EMOJI_RE = re.compile(r":([a-z][a-z0-9_]*):")
|
|
31
29
|
|
|
32
|
-
# Bare emoji shortcode →
|
|
33
|
-
# BMP-only where a reasonable equivalent exists; supplementary-plane emoji
|
|
34
|
-
# are excluded to preserve MySQL utf8 Confluence compatibility.
|
|
30
|
+
# Bare emoji shortcode → Unicode symbol (or "" to strip silently).
|
|
35
31
|
_STANDARD_EMOJI_MAP: dict[str, str] = {
|
|
36
32
|
# Alerts / status
|
|
37
33
|
"warning": "⚠", # U+26A0
|
|
38
|
-
"rotating_light": "
|
|
34
|
+
"rotating_light": "🚨", # U+1F6A8
|
|
39
35
|
"octagonal_sign": "⛔", # U+26D4
|
|
40
36
|
"no_entry": "⛔", # U+26D4
|
|
41
37
|
"no_entry_sign": "⛔",
|
|
42
38
|
"stop_sign": "⛔",
|
|
43
39
|
"information_source": "ℹ", # U+2139
|
|
44
40
|
# Checkmarks / marks
|
|
45
|
-
"white_check_mark": "✓", # U+2713
|
|
41
|
+
"white_check_mark": "✓", # U+2713
|
|
46
42
|
"heavy_check_mark": "✓", # U+2713
|
|
47
|
-
"x": "✗", # U+2717
|
|
43
|
+
"x": "✗", # U+2717
|
|
48
44
|
"heavy_multiplication_x": "✗",
|
|
49
45
|
# Objects — tools
|
|
50
|
-
"wrench": "
|
|
46
|
+
"wrench": "🔧", # U+1F527
|
|
51
47
|
"gear": "⚙", # U+2699
|
|
52
|
-
"hammer": "",
|
|
53
|
-
"hammer_and_wrench": "",
|
|
48
|
+
"hammer": "🔨", # U+1F528
|
|
49
|
+
"hammer_and_wrench": "🛠️", # U+1F6E0
|
|
54
50
|
# Work / business
|
|
55
|
-
"briefcase": "",
|
|
51
|
+
"briefcase": "💼", # U+1F4BC
|
|
56
52
|
# Nature / miscellaneous
|
|
57
53
|
"star": "★", # U+2605
|
|
58
54
|
"star2": "★",
|
|
59
|
-
"rocket": "",
|
|
60
|
-
"construction": "",
|
|
61
|
-
"tada": "",
|
|
62
|
-
"trophy": "",
|
|
63
|
-
"thinking": "",
|
|
64
|
-
"smile": "",
|
|
65
|
-
"laughing": "",
|
|
55
|
+
"rocket": "🚀", # U+1F680
|
|
56
|
+
"construction": "🚧", # U+1F6A7
|
|
57
|
+
"tada": "🎉", # U+1F389
|
|
58
|
+
"trophy": "🏆", # U+1F3C6
|
|
59
|
+
"thinking": "🤔", # U+1F914
|
|
60
|
+
"smile": "😄", # U+1F604
|
|
61
|
+
"laughing": "😆", # U+1F606
|
|
66
62
|
"heart": "♥", # U+2665
|
|
67
|
-
"fire": "",
|
|
68
|
-
"zap": "",
|
|
69
|
-
"bulb": "",
|
|
70
|
-
"computer": "",
|
|
71
|
-
"notebook": "",
|
|
72
|
-
"memo": "",
|
|
73
|
-
"clipboard": "",
|
|
74
|
-
"link": "",
|
|
75
|
-
"label": "",
|
|
76
|
-
"bookmark": "",
|
|
77
|
-
"chart_with_upwards_trend": "",
|
|
78
|
-
"bar_chart": "",
|
|
63
|
+
"fire": "🔥", # U+1F525
|
|
64
|
+
"zap": "⚡", # U+26A1
|
|
65
|
+
"bulb": "💡", # U+1F4A1
|
|
66
|
+
"computer": "💻", # U+1F4BB
|
|
67
|
+
"notebook": "📓", # U+1F4D3
|
|
68
|
+
"memo": "📝", # U+1F4DD
|
|
69
|
+
"clipboard": "📋", # U+1F4CB
|
|
70
|
+
"link": "🔗", # U+1F517
|
|
71
|
+
"label": "🏷️", # U+1F3F7
|
|
72
|
+
"bookmark": "🔖", # U+1F516
|
|
73
|
+
"chart_with_upwards_trend": "📈", # U+1F4C8
|
|
74
|
+
"bar_chart": "📊", # U+1F4CA
|
|
79
75
|
}
|
|
80
76
|
|
|
81
77
|
# Keyword → symbol. Keys must be lowercase single words (icon name segments).
|
|
82
|
-
# ALL values must be BMP characters (U+0000–U+FFFF) or "" (strip silently).
|
|
83
78
|
# Ordered so earlier, more-specific entries take priority where ambiguous.
|
|
84
79
|
_KEYWORD_MAP: dict[str, str | None] = {
|
|
85
|
-
# Status / validation
|
|
80
|
+
# Status / validation
|
|
86
81
|
"check": "✓", # U+2713
|
|
87
82
|
"done": "✓",
|
|
88
83
|
"complete": "✓",
|
|
@@ -103,98 +98,98 @@ _KEYWORD_MAP: dict[str, str | None] = {
|
|
|
103
98
|
# Navigation / directional
|
|
104
99
|
"arrow": None, # resolved with next segment — see _resolve()
|
|
105
100
|
"chevron": None,
|
|
106
|
-
# Security
|
|
107
|
-
"lock": "",
|
|
108
|
-
"security": "",
|
|
109
|
-
"shield": "",
|
|
110
|
-
"unlock": "",
|
|
111
|
-
"key": "",
|
|
101
|
+
# Security
|
|
102
|
+
"lock": "🔒", # U+1F512
|
|
103
|
+
"security": "🛡️", # U+1F6E0
|
|
104
|
+
"shield": "🛡️",
|
|
105
|
+
"unlock": "🔓", # U+1F513
|
|
106
|
+
"key": "🔑", # U+1F511
|
|
112
107
|
# Actions
|
|
113
108
|
"download": "↓", # U+2193
|
|
114
109
|
"upload": "↑", # U+2191
|
|
115
|
-
"refresh": "↻", # U+21BB
|
|
110
|
+
"refresh": "↻", # U+21BB
|
|
116
111
|
"sync": "↻",
|
|
117
112
|
"reload": "↻",
|
|
118
|
-
"search": "",
|
|
119
|
-
"magnify": "",
|
|
120
|
-
"edit": "✎", # U+270E
|
|
113
|
+
"search": "🔍", # U+1F50D
|
|
114
|
+
"magnify": "🔍",
|
|
115
|
+
"edit": "✎", # U+270E
|
|
121
116
|
"pencil": "✎",
|
|
122
117
|
"pen": "✎",
|
|
123
118
|
"copy": "", # strip
|
|
124
|
-
"clipboard": "",
|
|
125
|
-
"trash": "",
|
|
126
|
-
"delete": "",
|
|
119
|
+
"clipboard": "📋", # U+1F4CB
|
|
120
|
+
"trash": "🗑️", # U+1F5D1
|
|
121
|
+
"delete": "🗑️",
|
|
127
122
|
"add": "+",
|
|
128
123
|
"plus": "+",
|
|
129
|
-
"minus": "−", # U+2212
|
|
130
|
-
"link": "",
|
|
131
|
-
"chain": "",
|
|
124
|
+
"minus": "−", # U+2212
|
|
125
|
+
"link": "🔗", # U+1F517
|
|
126
|
+
"chain": "🔗",
|
|
132
127
|
# Objects / content
|
|
133
|
-
"star": "★", # U+2605
|
|
128
|
+
"star": "★", # U+2605
|
|
134
129
|
"favorite": "★",
|
|
135
|
-
"bookmark": "",
|
|
136
|
-
"heart": "♥", # U+2665
|
|
137
|
-
"fire": "",
|
|
138
|
-
"rocket": "",
|
|
139
|
-
"launch": "",
|
|
140
|
-
"home": "",
|
|
141
|
-
"settings": "⚙", # U+2699
|
|
130
|
+
"bookmark": "🔖", # U+1F516
|
|
131
|
+
"heart": "♥", # U+2665
|
|
132
|
+
"fire": "🔥", # U+1F525
|
|
133
|
+
"rocket": "🚀", # U+1F680
|
|
134
|
+
"launch": "🚀",
|
|
135
|
+
"home": "🏠", # U+1F3E0
|
|
136
|
+
"settings": "⚙", # U+2699
|
|
142
137
|
"cog": "⚙",
|
|
143
138
|
"gear": "⚙",
|
|
144
|
-
"wrench": "",
|
|
145
|
-
"email": "✉", # U+2709
|
|
139
|
+
"wrench": "🔧", # U+1F527
|
|
140
|
+
"email": "✉", # U+2709
|
|
146
141
|
"mail": "✉",
|
|
147
142
|
"envelope": "✉",
|
|
148
|
-
"phone": "☎", # U+260E
|
|
149
|
-
"clock": "",
|
|
150
|
-
"time": "",
|
|
151
|
-
"calendar": "",
|
|
152
|
-
"date": "",
|
|
153
|
-
"folder": "",
|
|
154
|
-
"file": "",
|
|
155
|
-
"document": "",
|
|
156
|
-
"code": "",
|
|
157
|
-
"terminal": "",
|
|
158
|
-
"database": "",
|
|
159
|
-
"cloud": "☁", # U+2601
|
|
160
|
-
"globe": "",
|
|
161
|
-
"world": "",
|
|
162
|
-
"earth": "",
|
|
163
|
-
"chart": "",
|
|
164
|
-
"graph": "",
|
|
165
|
-
"book": "",
|
|
166
|
-
"docs": "",
|
|
167
|
-
"note": "", # strip
|
|
168
|
-
"tag": "",
|
|
169
|
-
"label": "",
|
|
170
|
-
"flag": "",
|
|
143
|
+
"phone": "☎", # U+260E
|
|
144
|
+
"clock": "⏰", # U+23F0
|
|
145
|
+
"time": "⏰",
|
|
146
|
+
"calendar": "📅", # U+1F4C5
|
|
147
|
+
"date": "📅",
|
|
148
|
+
"folder": "📁", # U+1F4C1
|
|
149
|
+
"file": "📄", # U+1F4C4
|
|
150
|
+
"document": "📄",
|
|
151
|
+
"code": "💻", # U+1F4BB
|
|
152
|
+
"terminal": "💻",
|
|
153
|
+
"database": "🗄️", # U+1F5C4
|
|
154
|
+
"cloud": "☁", # U+2601
|
|
155
|
+
"globe": "🌍", # U+1F30D
|
|
156
|
+
"world": "🌍",
|
|
157
|
+
"earth": "🌍",
|
|
158
|
+
"chart": "📊", # U+1F4CA
|
|
159
|
+
"graph": "📊",
|
|
160
|
+
"book": "📖", # U+1F4D6
|
|
161
|
+
"docs": "📖",
|
|
162
|
+
"note": "", # strip — ambiguous; not the 📝 emoji
|
|
163
|
+
"tag": "🏷️", # U+1F3F7
|
|
164
|
+
"label": "🏷️",
|
|
165
|
+
"flag": "🚩", # U+1F6A9
|
|
171
166
|
"eye": "", # strip — was wrongly matching grid/view icons
|
|
172
|
-
"view": "", # strip — semantically ambiguous
|
|
173
|
-
"grid": "", # strip — layout/grid icons have no
|
|
174
|
-
"user": "",
|
|
175
|
-
"account": "",
|
|
176
|
-
"person": "",
|
|
177
|
-
"group": "",
|
|
178
|
-
"people": "",
|
|
179
|
-
"team": "",
|
|
180
|
-
"robot": "",
|
|
181
|
-
"bug": "",
|
|
167
|
+
"view": "", # strip — semantically ambiguous
|
|
168
|
+
"grid": "", # strip — layout/grid icons have no emoji analogue
|
|
169
|
+
"user": "👤", # U+1F464
|
|
170
|
+
"account": "👤",
|
|
171
|
+
"person": "👤",
|
|
172
|
+
"group": "👥", # U+1F465
|
|
173
|
+
"people": "👥",
|
|
174
|
+
"team": "👥",
|
|
175
|
+
"robot": "🤖", # U+1F916
|
|
176
|
+
"bug": "🐛", # U+1F41B
|
|
182
177
|
"test": "", # strip
|
|
183
|
-
"flask": "",
|
|
184
|
-
"lightbulb": "",
|
|
185
|
-
"idea": "",
|
|
186
|
-
"package": "",
|
|
187
|
-
"server": "",
|
|
178
|
+
"flask": "", # strip
|
|
179
|
+
"lightbulb": "💡", # U+1F4A1
|
|
180
|
+
"idea": "💡",
|
|
181
|
+
"package": "📦", # U+1F4E6
|
|
182
|
+
"server": "🖥️", # U+1F5A5
|
|
188
183
|
"network": "", # strip
|
|
189
|
-
"wifi": "",
|
|
184
|
+
"wifi": "", # strip
|
|
190
185
|
"battery": "", # strip
|
|
191
|
-
"image": "",
|
|
192
|
-
"video": "",
|
|
193
|
-
"music": "♪", # U+266A
|
|
186
|
+
"image": "🖼️", # U+1F5BC
|
|
187
|
+
"video": "🎥", # U+1F3A5
|
|
188
|
+
"music": "♪", # U+266A
|
|
194
189
|
"printer": "", # strip
|
|
195
|
-
"keyboard": "⌨", # U+2328
|
|
190
|
+
"keyboard": "⌨", # U+2328
|
|
196
191
|
"mouse": "", # strip
|
|
197
|
-
"monitor": "",
|
|
192
|
+
"monitor": "🖥️",
|
|
198
193
|
# Modifier suffixes — never meaningful on their own; always strip
|
|
199
194
|
"outline": "",
|
|
200
195
|
"variant": "",
|
|
@@ -136,6 +136,18 @@ class TestAdmonitionEmitter:
|
|
|
136
136
|
assert 'ac:name="expand"' in out
|
|
137
137
|
assert 'ac:name="panel"' not in out
|
|
138
138
|
|
|
139
|
+
def test_expanded_admonition_renders_as_regular_macro(self) -> None:
|
|
140
|
+
# ???+ (collapsible=True, expanded=True) has no Confluence equivalent for
|
|
141
|
+
# "expanded by default", so we degrade to a regular admonition macro.
|
|
142
|
+
out = emit((
|
|
143
|
+
Admonition(kind="note", title="Visible", children=(Paragraph((TextNode("body"),)),),
|
|
144
|
+
collapsible=True, expanded=True),
|
|
145
|
+
))
|
|
146
|
+
assert 'ac:name="expand"' not in out
|
|
147
|
+
assert 'ac:name="info"' in out
|
|
148
|
+
assert "Visible" in out
|
|
149
|
+
assert "body" in out
|
|
150
|
+
|
|
139
151
|
|
|
140
152
|
class TestContentTabsEmitter:
|
|
141
153
|
def test_tabs_render_as_expand_macros(self) -> None:
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""Tests for preprocess.icons — icon shortcode stripping/mapping.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
Confluence Cloud uses utf8mb4 and supports full Unicode including
|
|
4
|
+
supplementary-plane emoji (U+10000+). Shortcodes with no clear emoji
|
|
5
|
+
equivalent are stripped silently.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
8
|
from __future__ import annotations
|
|
@@ -29,23 +29,20 @@ class TestKnownMappings:
|
|
|
29
29
|
def test_close_maps_to_cross(self) -> None:
|
|
30
30
|
assert strip_icon_shortcodes(":material-close:") == "✗"
|
|
31
31
|
|
|
32
|
-
def
|
|
33
|
-
|
|
34
|
-
assert strip_icon_shortcodes(":material-lock:") == ""
|
|
32
|
+
def test_lock_maps_to_emoji(self) -> None:
|
|
33
|
+
assert strip_icon_shortcodes(":material-lock:") == "🔒"
|
|
35
34
|
|
|
36
|
-
def
|
|
37
|
-
assert strip_icon_shortcodes(":material-shield:") == ""
|
|
35
|
+
def test_shield_maps_to_emoji(self) -> None:
|
|
36
|
+
assert strip_icon_shortcodes(":material-shield:") == "🛡️"
|
|
38
37
|
|
|
39
|
-
def
|
|
40
|
-
|
|
41
|
-
assert strip_icon_shortcodes(":material-rocket-launch:") == ""
|
|
38
|
+
def test_rocket_maps_to_emoji(self) -> None:
|
|
39
|
+
assert strip_icon_shortcodes(":material-rocket-launch:") == "🚀"
|
|
42
40
|
|
|
43
41
|
def test_settings_maps_to_gear(self) -> None:
|
|
44
42
|
assert strip_icon_shortcodes(":material-cog:") == "⚙"
|
|
45
43
|
|
|
46
|
-
def
|
|
47
|
-
|
|
48
|
-
assert strip_icon_shortcodes(":material-magnify:") == ""
|
|
44
|
+
def test_search_maps_to_emoji(self) -> None:
|
|
45
|
+
assert strip_icon_shortcodes(":material-magnify:") == "🔍"
|
|
49
46
|
|
|
50
47
|
def test_refresh_maps_to_arrow(self) -> None:
|
|
51
48
|
assert strip_icon_shortcodes(":material-refresh:") == "↻"
|
|
@@ -84,18 +81,17 @@ class TestArrowMappings:
|
|
|
84
81
|
|
|
85
82
|
|
|
86
83
|
class TestBuggedIcons:
|
|
87
|
-
"""Regression tests for icons that
|
|
84
|
+
"""Regression tests for icons that should not produce wrong output."""
|
|
88
85
|
|
|
89
|
-
def
|
|
90
|
-
|
|
91
|
-
assert strip_icon_shortcodes(":material-link-variant:") == ""
|
|
86
|
+
def test_link_variant_maps_to_emoji(self) -> None:
|
|
87
|
+
assert strip_icon_shortcodes(":material-link-variant:") == "🔗"
|
|
92
88
|
|
|
93
89
|
def test_grid_view_outline_stripped(self) -> None:
|
|
94
|
-
#
|
|
90
|
+
# grid/view have no meaningful emoji analogue
|
|
95
91
|
assert strip_icon_shortcodes(":material-grid-view-outline:") == ""
|
|
96
92
|
|
|
97
|
-
def
|
|
98
|
-
assert strip_icon_shortcodes(":material-link:") == ""
|
|
93
|
+
def test_link_maps_to_emoji(self) -> None:
|
|
94
|
+
assert strip_icon_shortcodes(":material-link:") == "🔗"
|
|
99
95
|
|
|
100
96
|
def test_view_stripped(self) -> None:
|
|
101
97
|
assert strip_icon_shortcodes(":material-view-dashboard:") == ""
|
|
@@ -124,21 +120,26 @@ class TestUnknownIcons:
|
|
|
124
120
|
assert strip_icon_shortcodes(":fontawesome-brands-github:") == ""
|
|
125
121
|
|
|
126
122
|
|
|
127
|
-
class
|
|
128
|
-
"""
|
|
123
|
+
class TestEmojiMappings:
|
|
124
|
+
"""Supplementary-plane emoji now map to real emoji (Cloud utf8mb4 support)."""
|
|
129
125
|
|
|
130
|
-
def
|
|
131
|
-
|
|
126
|
+
def test_fire_maps_to_emoji(self) -> None:
|
|
127
|
+
assert strip_icon_shortcodes(":material-fire:") == "🔥"
|
|
132
128
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
129
|
+
def test_lightbulb_maps_to_emoji(self) -> None:
|
|
130
|
+
assert strip_icon_shortcodes(":material-lightbulb:") == "💡"
|
|
131
|
+
|
|
132
|
+
def test_bug_maps_to_emoji(self) -> None:
|
|
133
|
+
assert strip_icon_shortcodes(":material-bug:") == "🐛"
|
|
134
|
+
|
|
135
|
+
def test_package_maps_to_emoji(self) -> None:
|
|
136
|
+
assert strip_icon_shortcodes(":material-package:") == "📦"
|
|
137
|
+
|
|
138
|
+
def test_account_maps_to_emoji(self) -> None:
|
|
139
|
+
assert strip_icon_shortcodes(":material-account:") == "👤"
|
|
140
|
+
|
|
141
|
+
def test_robot_maps_to_emoji(self) -> None:
|
|
142
|
+
assert strip_icon_shortcodes(":material-robot:") == "🤖"
|
|
142
143
|
|
|
143
144
|
|
|
144
145
|
class TestInlineReplacement:
|
|
@@ -162,14 +163,14 @@ class TestInlineReplacement:
|
|
|
162
163
|
class TestStandardEmoji:
|
|
163
164
|
"""Tests for bare emoji shortcodes like :rotating_light:."""
|
|
164
165
|
|
|
165
|
-
def
|
|
166
|
-
assert strip_icon_shortcodes(":rotating_light:") == "
|
|
166
|
+
def test_rotating_light_maps_to_siren(self) -> None:
|
|
167
|
+
assert strip_icon_shortcodes(":rotating_light:") == "🚨"
|
|
167
168
|
|
|
168
169
|
def test_octagonal_sign_maps_to_no_entry(self) -> None:
|
|
169
170
|
assert strip_icon_shortcodes(":octagonal_sign:") == "⛔"
|
|
170
171
|
|
|
171
|
-
def
|
|
172
|
-
assert strip_icon_shortcodes(":wrench:") == "
|
|
172
|
+
def test_wrench_maps_to_wrench_emoji(self) -> None:
|
|
173
|
+
assert strip_icon_shortcodes(":wrench:") == "🔧"
|
|
173
174
|
|
|
174
175
|
def test_information_source_maps_to_info(self) -> None:
|
|
175
176
|
assert strip_icon_shortcodes(":information_source:") == "ℹ"
|
|
@@ -180,8 +181,8 @@ class TestStandardEmoji:
|
|
|
180
181
|
def test_x_maps_to_cross(self) -> None:
|
|
181
182
|
assert strip_icon_shortcodes(":x:") == "✗"
|
|
182
183
|
|
|
183
|
-
def
|
|
184
|
-
assert strip_icon_shortcodes(":briefcase:") == ""
|
|
184
|
+
def test_briefcase_maps_to_emoji(self) -> None:
|
|
185
|
+
assert strip_icon_shortcodes(":briefcase:") == "💼"
|
|
185
186
|
|
|
186
187
|
def test_unknown_shortcode_unchanged(self) -> None:
|
|
187
188
|
assert strip_icon_shortcodes(":unknown_emoji_xyz:") == ":unknown_emoji_xyz:"
|
|
@@ -195,11 +196,7 @@ class TestStandardEmoji:
|
|
|
195
196
|
result = strip_icon_shortcodes(":material-check-circle:")
|
|
196
197
|
assert result == "✓"
|
|
197
198
|
|
|
198
|
-
def
|
|
199
|
+
def test_all_standard_emoji_values_are_strings(self) -> None:
|
|
199
200
|
from mkdocs_to_confluence.preprocess.icons import _STANDARD_EMOJI_MAP
|
|
200
201
|
for name, symbol in _STANDARD_EMOJI_MAP.items():
|
|
201
|
-
|
|
202
|
-
assert ord(ch) <= 0xFFFF, (
|
|
203
|
-
f"_STANDARD_EMOJI_MAP[{name!r}] contains supplementary-plane "
|
|
204
|
-
f"character U+{ord(ch):04X} — use BMP or empty string"
|
|
205
|
-
)
|
|
202
|
+
assert isinstance(symbol, str), f"_STANDARD_EMOJI_MAP[{name!r}] is not a string"
|
|
@@ -515,6 +515,21 @@ class TestAdmonitions:
|
|
|
515
515
|
assert isinstance(adm, Admonition)
|
|
516
516
|
assert adm.collapsible is True
|
|
517
517
|
|
|
518
|
+
def test_question_mark_plus_is_expanded(self) -> None:
|
|
519
|
+
adm = first(parse("???+ note\n Body.\n"), Admonition)
|
|
520
|
+
assert isinstance(adm, Admonition)
|
|
521
|
+
assert adm.expanded is True
|
|
522
|
+
|
|
523
|
+
def test_question_mark_no_plus_is_not_expanded(self) -> None:
|
|
524
|
+
adm = first(parse("??? note\n Body.\n"), Admonition)
|
|
525
|
+
assert isinstance(adm, Admonition)
|
|
526
|
+
assert adm.expanded is False
|
|
527
|
+
|
|
528
|
+
def test_bang_is_not_expanded(self) -> None:
|
|
529
|
+
adm = first(parse("!!! note\n Body.\n"), Admonition)
|
|
530
|
+
assert isinstance(adm, Admonition)
|
|
531
|
+
assert adm.expanded is False
|
|
532
|
+
|
|
518
533
|
def test_body_paragraph_parsed(self) -> None:
|
|
519
534
|
adm = first(parse("!!! note\n Body text here.\n"), Admonition)
|
|
520
535
|
assert isinstance(adm, Admonition)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs2confluence.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs2confluence.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs2confluence.egg-info/requires.txt
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs2confluence.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/emitter/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/loader/__init__.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/loader/config.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/loader/extra_css.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/parser/__init__.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/pdf/__init__.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/pdf/generator.py
RENAMED
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/preprocess/__init__.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/preprocess/abbrevs.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/preprocess/fence.py
RENAMED
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/preprocess/includes.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/preprocess/linkdefs.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/preview/__init__.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/preview/render.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/preview/server.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/publisher/__init__.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/publisher/client.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/publisher/pipeline.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/transforms/__init__.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/transforms/abbrevs.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/transforms/assets.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/transforms/editlink.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/src/mkdocs_to_confluence/transforms/images.py
RENAMED
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.7.7 → mkdocs2confluence-0.7.9}/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
|
|
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
|