mkdocs2confluence 0.7.9__tar.gz → 0.7.11__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.9/src/mkdocs2confluence.egg-info → mkdocs2confluence-0.7.11}/PKG-INFO +3 -3
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/README.md +2 -2
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/pyproject.toml +1 -1
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11/src/mkdocs2confluence.egg-info}/PKG-INFO +3 -3
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/emitter/xhtml.py +45 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/ir/nodes.py +34 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/transforms/abbrevs.py +66 -51
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/tests/test_abbrevs.py +75 -122
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/LICENSE +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/setup.cfg +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs2confluence.egg-info/SOURCES.txt +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs2confluence.egg-info/dependency_links.txt +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs2confluence.egg-info/entry_points.txt +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs2confluence.egg-info/requires.txt +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs2confluence.egg-info/top_level.txt +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/__init__.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/cli.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/emitter/__init__.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/ir/__init__.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/ir/document.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/ir/treeutil.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/loader/__init__.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/loader/config.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/loader/extra_css.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/loader/nav.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/loader/page.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/parser/__init__.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/parser/markdown.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/pdf/__init__.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/pdf/generator.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/pdf/render.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/preprocess/__init__.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/preprocess/abbrevs.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/preprocess/fence.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/preprocess/frontmatter.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/preprocess/icons.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/preprocess/includes.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/preprocess/linkdefs.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/preview/__init__.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/preview/render.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/preview/server.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/publisher/__init__.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/publisher/client.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/publisher/pipeline.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/transforms/__init__.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/transforms/assets.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/transforms/editlink.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/transforms/images.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/transforms/internallinks.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/transforms/mermaid.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/tests/test_cli.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/tests/test_editlink.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/tests/test_emitter.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/tests/test_extra_css.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/tests/test_frontmatter.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/tests/test_icons.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/tests/test_images.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/tests/test_internallinks.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/tests/test_ir.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/tests/test_linkdefs.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/tests/test_loader.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/tests/test_mermaid.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/tests/test_page_loader.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/tests/test_parser.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/tests/test_pdf.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/tests/test_preprocess.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/tests/test_preview.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/tests/test_publish_client.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/tests/test_publish_config.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/tests/test_publish_pipeline.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/tests/test_server.py +0 -0
- {mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/tests/test_treeutil.py +0 -0
{mkdocs2confluence-0.7.9/src/mkdocs2confluence.egg-info → mkdocs2confluence-0.7.11}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mkdocs2confluence
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.11
|
|
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
|
|
@@ -355,7 +355,7 @@ If `repo_url` + `edit_uri` are set in `mkdocs.yml`, an **Edit Source** row links
|
|
|
355
355
|
|
|
356
356
|
### Abbreviation expansion
|
|
357
357
|
|
|
358
|
-
MkDocs abbreviation definitions (`*[ABBR]: Full term`) are
|
|
358
|
+
MkDocs abbreviation definitions (`*[ABBR]: Full term`) are rendered as inline Confluence **footnotes**. The **first occurrence** of each abbreviation in body text is annotated with a footnote macro — Confluence renders it as a superscript number and collects all definitions at the bottom of the page. Subsequent occurrences are left as plain text. Abbreviations that only appear in headings or other non-expandable contexts are collected into an auto-appended **Glossary** section as a fallback.
|
|
359
359
|
|
|
360
360
|
---
|
|
361
361
|
|
|
@@ -364,7 +364,7 @@ MkDocs abbreviation definitions (`*[ABBR]: Full term`) are expanded inline — C
|
|
|
364
364
|
| Feature | Behaviour |
|
|
365
365
|
|---|---|
|
|
366
366
|
| **Admonition styling** | `tip`, `info`, `warning`, `note` use Confluence's fixed native macro colours. `danger`, `error`, `bug` use a custom red `panel` macro with 🚨 prefix. All other types are mapped to the nearest native macro. |
|
|
367
|
-
| **Abbreviation tooltips** | No native tooltip support. First occurrence
|
|
367
|
+
| **Abbreviation tooltips** | No native tooltip support. First occurrence annotated with an inline Confluence footnote; definition collected at the bottom of the page. |
|
|
368
368
|
| **Page ordering** | Confluence sorts child pages alphabetically; the v2 REST API has no write endpoint for ordering. |
|
|
369
369
|
| **Code language aliases** | Short aliases (`py`, `js`, `yml`, `ts`, `sh`) are passed through as-is; Confluence requires full language names for syntax highlighting. |
|
|
370
370
|
| **Unrecognised blocks** | Preserved as a visible `warning` macro — no content is silently lost. |
|
|
@@ -315,7 +315,7 @@ If `repo_url` + `edit_uri` are set in `mkdocs.yml`, an **Edit Source** row links
|
|
|
315
315
|
|
|
316
316
|
### Abbreviation expansion
|
|
317
317
|
|
|
318
|
-
MkDocs abbreviation definitions (`*[ABBR]: Full term`) are
|
|
318
|
+
MkDocs abbreviation definitions (`*[ABBR]: Full term`) are rendered as inline Confluence **footnotes**. The **first occurrence** of each abbreviation in body text is annotated with a footnote macro — Confluence renders it as a superscript number and collects all definitions at the bottom of the page. Subsequent occurrences are left as plain text. Abbreviations that only appear in headings or other non-expandable contexts are collected into an auto-appended **Glossary** section as a fallback.
|
|
319
319
|
|
|
320
320
|
---
|
|
321
321
|
|
|
@@ -324,7 +324,7 @@ MkDocs abbreviation definitions (`*[ABBR]: Full term`) are expanded inline — C
|
|
|
324
324
|
| Feature | Behaviour |
|
|
325
325
|
|---|---|
|
|
326
326
|
| **Admonition styling** | `tip`, `info`, `warning`, `note` use Confluence's fixed native macro colours. `danger`, `error`, `bug` use a custom red `panel` macro with 🚨 prefix. All other types are mapped to the nearest native macro. |
|
|
327
|
-
| **Abbreviation tooltips** | No native tooltip support. First occurrence
|
|
327
|
+
| **Abbreviation tooltips** | No native tooltip support. First occurrence annotated with an inline Confluence footnote; definition collected at the bottom of the page. |
|
|
328
328
|
| **Page ordering** | Confluence sorts child pages alphabetically; the v2 REST API has no write endpoint for ordering. |
|
|
329
329
|
| **Code language aliases** | Short aliases (`py`, `js`, `yml`, `ts`, `sh`) are passed through as-is; Confluence requires full language names for syntax highlighting. |
|
|
330
330
|
| **Unrecognised blocks** | Preserved as a visible `warning` macro — no content is silently lost. |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "mkdocs2confluence"
|
|
3
|
-
version = "0.7.
|
|
3
|
+
version = "0.7.11"
|
|
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.9 → mkdocs2confluence-0.7.11/src/mkdocs2confluence.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mkdocs2confluence
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.11
|
|
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
|
|
@@ -355,7 +355,7 @@ If `repo_url` + `edit_uri` are set in `mkdocs.yml`, an **Edit Source** row links
|
|
|
355
355
|
|
|
356
356
|
### Abbreviation expansion
|
|
357
357
|
|
|
358
|
-
MkDocs abbreviation definitions (`*[ABBR]: Full term`) are
|
|
358
|
+
MkDocs abbreviation definitions (`*[ABBR]: Full term`) are rendered as inline Confluence **footnotes**. The **first occurrence** of each abbreviation in body text is annotated with a footnote macro — Confluence renders it as a superscript number and collects all definitions at the bottom of the page. Subsequent occurrences are left as plain text. Abbreviations that only appear in headings or other non-expandable contexts are collected into an auto-appended **Glossary** section as a fallback.
|
|
359
359
|
|
|
360
360
|
---
|
|
361
361
|
|
|
@@ -364,7 +364,7 @@ MkDocs abbreviation definitions (`*[ABBR]: Full term`) are expanded inline — C
|
|
|
364
364
|
| Feature | Behaviour |
|
|
365
365
|
|---|---|
|
|
366
366
|
| **Admonition styling** | `tip`, `info`, `warning`, `note` use Confluence's fixed native macro colours. `danger`, `error`, `bug` use a custom red `panel` macro with 🚨 prefix. All other types are mapped to the nearest native macro. |
|
|
367
|
-
| **Abbreviation tooltips** | No native tooltip support. First occurrence
|
|
367
|
+
| **Abbreviation tooltips** | No native tooltip support. First occurrence annotated with an inline Confluence footnote; definition collected at the bottom of the page. |
|
|
368
368
|
| **Page ordering** | Confluence sorts child pages alphabetically; the v2 REST API has no write endpoint for ordering. |
|
|
369
369
|
| **Code language aliases** | Short aliases (`py`, `js`, `yml`, `ts`, `sh`) are passed through as-is; Confluence requires full language names for syntax highlighting. |
|
|
370
370
|
| **Unrecognised blocks** | Preserved as a visible `warning` macro — no content is silently lost. |
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/emitter/xhtml.py
RENAMED
|
@@ -22,6 +22,8 @@ from typing import Sequence
|
|
|
22
22
|
from urllib.parse import urlparse
|
|
23
23
|
|
|
24
24
|
from mkdocs_to_confluence.ir.nodes import (
|
|
25
|
+
AbbrevFootnoteNode,
|
|
26
|
+
AbbrevGlossaryBlock,
|
|
25
27
|
Admonition,
|
|
26
28
|
BlockQuote,
|
|
27
29
|
BoldNode,
|
|
@@ -190,6 +192,8 @@ def _emit_node(node: IRNode) -> str:
|
|
|
190
192
|
return _emit_front_matter(node)
|
|
191
193
|
if isinstance(node, FootnoteBlock):
|
|
192
194
|
return _emit_footnote_block(node)
|
|
195
|
+
if isinstance(node, AbbrevGlossaryBlock):
|
|
196
|
+
return _emit_abbrev_glossary_block(node)
|
|
193
197
|
if isinstance(node, GridCards):
|
|
194
198
|
return _emit_grid_cards(node)
|
|
195
199
|
if isinstance(node, UnsupportedBlock):
|
|
@@ -555,6 +559,45 @@ def _emit_footnote_ref(node: FootnoteRef) -> str:
|
|
|
555
559
|
)
|
|
556
560
|
|
|
557
561
|
|
|
562
|
+
def _emit_abbrev_footnote(node: AbbrevFootnoteNode) -> str:
|
|
563
|
+
"""Inline: ABBR + superscript anchor-link to the glossary entry."""
|
|
564
|
+
anchor = html.escape(f"abbr-{node.number}")
|
|
565
|
+
num = html.escape(str(node.number))
|
|
566
|
+
term = html.escape(node.abbr)
|
|
567
|
+
return (
|
|
568
|
+
f"{term}"
|
|
569
|
+
f"<sup>"
|
|
570
|
+
f'<ac:link ac:anchor="{anchor}">'
|
|
571
|
+
f"<ac:plain-text-link-body><![CDATA[{num}]]></ac:plain-text-link-body>"
|
|
572
|
+
f"</ac:link>"
|
|
573
|
+
f"</sup>"
|
|
574
|
+
)
|
|
575
|
+
|
|
576
|
+
|
|
577
|
+
def _emit_abbrev_glossary_block(node: AbbrevGlossaryBlock) -> str:
|
|
578
|
+
"""End-of-page abbreviations list with Confluence anchor targets."""
|
|
579
|
+
parts: list[str] = ["<hr />\n<h6>Abbreviations</h6>\n"]
|
|
580
|
+
if node.footnoted:
|
|
581
|
+
parts.append("<ol>\n")
|
|
582
|
+
for fn in node.footnoted:
|
|
583
|
+
anchor = html.escape(f"abbr-{fn.number}")
|
|
584
|
+
anchor_macro = (
|
|
585
|
+
f'<ac:structured-macro ac:name="anchor">'
|
|
586
|
+
f'<ac:parameter ac:name=""><![CDATA[{anchor}]]></ac:parameter>'
|
|
587
|
+
f"</ac:structured-macro>"
|
|
588
|
+
)
|
|
589
|
+
abbr = html.escape(fn.abbr)
|
|
590
|
+
defn = html.escape(fn.definition)
|
|
591
|
+
parts.append(f"<li>{anchor_macro}<strong>{abbr}</strong> — {defn}</li>\n")
|
|
592
|
+
parts.append("</ol>\n")
|
|
593
|
+
if node.extras:
|
|
594
|
+
parts.append("<ul>\n")
|
|
595
|
+
for abbr, defn in node.extras:
|
|
596
|
+
parts.append(f"<li><strong>{html.escape(abbr)}</strong> — {html.escape(defn)}</li>\n")
|
|
597
|
+
parts.append("</ul>\n")
|
|
598
|
+
return "".join(parts)
|
|
599
|
+
|
|
600
|
+
|
|
558
601
|
def _emit_footnote_block(node: FootnoteBlock) -> str:
|
|
559
602
|
"""Footnotes section: heading + ordered list with anchor targets."""
|
|
560
603
|
items: list[str] = []
|
|
@@ -613,6 +656,8 @@ def _emit_inline(node: IRNode) -> str:
|
|
|
613
656
|
return _emit_image(node)
|
|
614
657
|
if isinstance(node, FootnoteRef):
|
|
615
658
|
return _emit_footnote_ref(node)
|
|
659
|
+
if isinstance(node, AbbrevFootnoteNode):
|
|
660
|
+
return _emit_abbrev_footnote(node)
|
|
616
661
|
if isinstance(node, LineBreakNode):
|
|
617
662
|
return "<br />"
|
|
618
663
|
if isinstance(node, InlineHtmlNode):
|
|
@@ -428,6 +428,40 @@ class FrontMatter(IRNode):
|
|
|
428
428
|
site_url: str | None = None
|
|
429
429
|
|
|
430
430
|
|
|
431
|
+
# ── Abbreviation footnotes ────────────────────────────────────────────────────
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
@dataclass(frozen=True)
|
|
435
|
+
class AbbrevFootnoteNode(IRNode):
|
|
436
|
+
"""Inline: abbreviated term with a superscript anchor-link to the glossary.
|
|
437
|
+
|
|
438
|
+
The emitter renders ``ABBR<sup>[N]</sup>`` where ``[N]`` links to the
|
|
439
|
+
corresponding entry in the end-of-page :class:`AbbrevGlossaryBlock`.
|
|
440
|
+
"""
|
|
441
|
+
|
|
442
|
+
abbr: str
|
|
443
|
+
definition: str
|
|
444
|
+
number: int # 1-based, assigned by the transform in order of first encounter
|
|
445
|
+
|
|
446
|
+
|
|
447
|
+
@dataclass(frozen=True)
|
|
448
|
+
class AbbrevGlossaryBlock(IRNode):
|
|
449
|
+
"""End-of-page abbreviations reference block.
|
|
450
|
+
|
|
451
|
+
Rendered as a numbered list (with Confluence anchor targets for the
|
|
452
|
+
back-links) followed by an optional bullet list of abbreviations that
|
|
453
|
+
only appeared in headings or other non-expandable contexts.
|
|
454
|
+
|
|
455
|
+
Attributes:
|
|
456
|
+
footnoted: Abbreviations annotated inline, ordered by first encounter.
|
|
457
|
+
extras: ``(abbr, definition)`` pairs for abbreviations that could
|
|
458
|
+
not be annotated inline, sorted alphabetically.
|
|
459
|
+
"""
|
|
460
|
+
|
|
461
|
+
footnoted: tuple[AbbrevFootnoteNode, ...]
|
|
462
|
+
extras: tuple[tuple[str, str], ...]
|
|
463
|
+
|
|
464
|
+
|
|
431
465
|
# ── Footnotes ────────────────────────────────────────────────────────────────
|
|
432
466
|
|
|
433
467
|
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/transforms/abbrevs.py
RENAMED
|
@@ -3,17 +3,19 @@
|
|
|
3
3
|
Collects ``*[ABBR]: definition`` pairs (extracted by
|
|
4
4
|
:mod:`mkdocs_to_confluence.preprocess.abbrevs`) and walks the IR tree to:
|
|
5
5
|
|
|
6
|
-
1. **
|
|
7
|
-
paragraphs, list items, table body cells, blockquotes — by
|
|
8
|
-
``
|
|
6
|
+
1. **Annotate** the first occurrence of each abbreviation in *safe* body nodes —
|
|
7
|
+
paragraphs, list items, table body cells, blockquotes — by inserting an
|
|
8
|
+
inline Confluence ``footnote`` macro immediately after the term. Confluence
|
|
9
|
+
renders this as a superscript number and collects all definitions at the
|
|
10
|
+
bottom of the page.
|
|
9
11
|
|
|
10
12
|
2. **Skip** structural/title nodes where expansion would look odd:
|
|
11
13
|
section headings, table header cells, admonition/panel titles, code spans,
|
|
12
14
|
and link text.
|
|
13
15
|
|
|
14
16
|
3. **Append a Glossary section** at the end of the page for any abbreviation
|
|
15
|
-
that was detected in the page text but could not be
|
|
16
|
-
|
|
17
|
+
that was detected in the page text but could not be footnoted because it
|
|
18
|
+
only appeared in skipped contexts (headings, table headers, etc.).
|
|
17
19
|
|
|
18
20
|
Entry point
|
|
19
21
|
-----------
|
|
@@ -27,13 +29,14 @@ import re
|
|
|
27
29
|
from dataclasses import replace
|
|
28
30
|
|
|
29
31
|
from mkdocs_to_confluence.ir.nodes import (
|
|
32
|
+
AbbrevFootnoteNode,
|
|
33
|
+
AbbrevGlossaryBlock,
|
|
30
34
|
Admonition,
|
|
31
35
|
BlockQuote,
|
|
32
36
|
BoldNode,
|
|
33
37
|
BulletList,
|
|
34
38
|
ContentTabs,
|
|
35
39
|
Expandable,
|
|
36
|
-
HorizontalRule,
|
|
37
40
|
IRNode,
|
|
38
41
|
ItalicNode,
|
|
39
42
|
LinkNode,
|
|
@@ -57,28 +60,45 @@ class _State:
|
|
|
57
60
|
|
|
58
61
|
def __init__(self, abbrevs: dict[str, str]) -> None:
|
|
59
62
|
self.abbrevs = abbrevs
|
|
60
|
-
self.
|
|
63
|
+
self._expanded_list: list[str] = [] # ordered by first encounter
|
|
64
|
+
self._expanded_set: set[str] = set() # fast membership test
|
|
61
65
|
# Pre-compile word-boundary patterns once.
|
|
62
66
|
self._patterns: dict[str, re.Pattern[str]] = {
|
|
63
67
|
abbr: re.compile(r"\b" + re.escape(abbr) + r"\b")
|
|
64
68
|
for abbr in abbrevs
|
|
65
69
|
}
|
|
66
70
|
|
|
67
|
-
|
|
68
|
-
|
|
71
|
+
@property
|
|
72
|
+
def expanded(self) -> set[str]:
|
|
73
|
+
return self._expanded_set
|
|
69
74
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
75
|
+
def expand_to_nodes(self, text: str) -> tuple[IRNode, ...]:
|
|
76
|
+
"""Split *text* around the first unexpanded abbreviation.
|
|
77
|
+
|
|
78
|
+
Returns a mix of :class:`TextNode` and :class:`AbbrevFootnoteNode`.
|
|
79
|
+
Each abbreviation is footnoted at most once per page.
|
|
73
80
|
"""
|
|
74
|
-
|
|
75
|
-
|
|
81
|
+
best: tuple[int, int, str] | None = None
|
|
82
|
+
for abbr in self.abbrevs:
|
|
83
|
+
if abbr in self._expanded_set:
|
|
76
84
|
continue
|
|
77
|
-
|
|
78
|
-
if
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
85
|
+
m = self._patterns[abbr].search(text)
|
|
86
|
+
if m and (best is None or m.start() < best[0]):
|
|
87
|
+
best = (m.start(), m.end(), abbr)
|
|
88
|
+
|
|
89
|
+
if best is None:
|
|
90
|
+
return (TextNode(text),) if text else ()
|
|
91
|
+
|
|
92
|
+
start, end, abbr = best
|
|
93
|
+
self._expanded_list.append(abbr)
|
|
94
|
+
self._expanded_set.add(abbr)
|
|
95
|
+
number = len(self._expanded_list) # 1-based
|
|
96
|
+
nodes: list[IRNode] = []
|
|
97
|
+
if text[:start]:
|
|
98
|
+
nodes.append(TextNode(text[:start]))
|
|
99
|
+
nodes.append(AbbrevFootnoteNode(abbr=abbr, definition=self.abbrevs[abbr], number=number))
|
|
100
|
+
nodes.extend(self.expand_to_nodes(text[end:]))
|
|
101
|
+
return tuple(nodes)
|
|
82
102
|
|
|
83
103
|
|
|
84
104
|
# ── Block-level transform ─────────────────────────────────────────────────────
|
|
@@ -151,22 +171,25 @@ def _transform_table_cell(cell: TableCell, state: _State) -> TableCell:
|
|
|
151
171
|
|
|
152
172
|
|
|
153
173
|
def _inline(nodes: tuple[IRNode, ...], state: _State, safe: bool) -> tuple[IRNode, ...]:
|
|
154
|
-
|
|
174
|
+
result: list[IRNode] = []
|
|
175
|
+
for n in nodes:
|
|
176
|
+
result.extend(_transform_inline(n, state, safe))
|
|
177
|
+
return tuple(result)
|
|
155
178
|
|
|
156
179
|
|
|
157
|
-
def _transform_inline(node: IRNode, state: _State, safe: bool) -> IRNode:
|
|
180
|
+
def _transform_inline(node: IRNode, state: _State, safe: bool) -> tuple[IRNode, ...]:
|
|
158
181
|
if isinstance(node, TextNode):
|
|
159
|
-
return
|
|
182
|
+
return state.expand_to_nodes(node.text) if safe else (node,)
|
|
160
183
|
|
|
161
184
|
if isinstance(node, (BoldNode, ItalicNode, StrikethroughNode)):
|
|
162
|
-
return replace(node, children=_inline(node.children, state, safe))
|
|
185
|
+
return (replace(node, children=_inline(node.children, state, safe)),)
|
|
163
186
|
|
|
164
187
|
if isinstance(node, LinkNode):
|
|
165
188
|
# Expanding inside link text could break the anchor label — skip.
|
|
166
|
-
return replace(node, children=_inline(node.children, state, safe=False))
|
|
189
|
+
return (replace(node, children=_inline(node.children, state, safe=False)),)
|
|
167
190
|
|
|
168
191
|
# CodeInlineNode, ImageNode — never expand.
|
|
169
|
-
return node
|
|
192
|
+
return (node,)
|
|
170
193
|
|
|
171
194
|
|
|
172
195
|
# ── Glossary builder ──────────────────────────────────────────────────────────
|
|
@@ -181,21 +204,6 @@ def _find_mentioned(text: str, abbrevs: dict[str, str]) -> set[str]:
|
|
|
181
204
|
}
|
|
182
205
|
|
|
183
206
|
|
|
184
|
-
def _build_glossary_section(terms: dict[str, str]) -> tuple[IRNode, ...]:
|
|
185
|
-
"""Return an HR + h6 ``Section`` listing abbreviations that could not be expanded inline."""
|
|
186
|
-
items = tuple(
|
|
187
|
-
ListItem(children=(Paragraph(children=(TextNode(f"{abbr} — {defn}"),)),))
|
|
188
|
-
for abbr, defn in sorted(terms.items())
|
|
189
|
-
)
|
|
190
|
-
section = Section(
|
|
191
|
-
level=6,
|
|
192
|
-
anchor="glossary",
|
|
193
|
-
title=(TextNode("Glossary"),),
|
|
194
|
-
children=(BulletList(items=items),),
|
|
195
|
-
)
|
|
196
|
-
return (HorizontalRule(), section)
|
|
197
|
-
|
|
198
|
-
|
|
199
207
|
# ── Public API ────────────────────────────────────────────────────────────────
|
|
200
208
|
|
|
201
209
|
|
|
@@ -213,13 +221,15 @@ def apply_abbreviations(
|
|
|
213
221
|
:func:`~mkdocs_to_confluence.preprocess.abbrevs.extract_abbreviations`.
|
|
214
222
|
page_text: The preprocessed page text (after stripping abbreviation
|
|
215
223
|
definition lines) used to detect which abbreviations are
|
|
216
|
-
actually present on the page.
|
|
217
|
-
abbreviations need a glossary entry.
|
|
224
|
+
actually present on the page.
|
|
218
225
|
|
|
219
226
|
Returns:
|
|
220
|
-
Modified node tuple.
|
|
221
|
-
|
|
222
|
-
|
|
227
|
+
Modified node tuple. Abbreviations in body text receive an inline
|
|
228
|
+
superscript anchor-link (:class:`AbbrevFootnoteNode`). An
|
|
229
|
+
:class:`AbbrevGlossaryBlock` is appended when any abbreviation was
|
|
230
|
+
mentioned on the page, listing all footnoted entries (with anchor
|
|
231
|
+
targets for the back-links) plus any abbreviations that only appeared
|
|
232
|
+
in headings or other non-expandable contexts.
|
|
223
233
|
"""
|
|
224
234
|
if not abbrevs:
|
|
225
235
|
return nodes
|
|
@@ -228,12 +238,17 @@ def apply_abbreviations(
|
|
|
228
238
|
transformed = tuple(_transform_block(n, state) for n in nodes)
|
|
229
239
|
|
|
230
240
|
mentioned = _find_mentioned(page_text, abbrevs)
|
|
231
|
-
|
|
232
|
-
abbr
|
|
233
|
-
for abbr in
|
|
234
|
-
|
|
241
|
+
footnoted = tuple(
|
|
242
|
+
AbbrevFootnoteNode(abbr=abbr, definition=abbrevs[abbr], number=i + 1)
|
|
243
|
+
for i, abbr in enumerate(state._expanded_list)
|
|
244
|
+
)
|
|
245
|
+
extras = tuple(
|
|
246
|
+
(abbr, abbrevs[abbr])
|
|
247
|
+
for abbr in sorted(mentioned - state._expanded_set)
|
|
248
|
+
)
|
|
235
249
|
|
|
236
|
-
if
|
|
237
|
-
transformed = transformed +
|
|
250
|
+
if footnoted or extras:
|
|
251
|
+
transformed = transformed + (AbbrevGlossaryBlock(footnoted=footnoted, extras=extras),)
|
|
238
252
|
|
|
239
253
|
return transformed
|
|
254
|
+
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from mkdocs_to_confluence.ir.nodes import (
|
|
6
|
+
AbbrevFootnoteNode,
|
|
7
|
+
AbbrevGlossaryBlock,
|
|
6
8
|
Admonition,
|
|
7
9
|
BoldNode,
|
|
8
|
-
BulletList,
|
|
9
10
|
CodeBlock,
|
|
10
|
-
HorizontalRule,
|
|
11
11
|
LinkNode,
|
|
12
12
|
Paragraph,
|
|
13
13
|
Section,
|
|
@@ -81,26 +81,42 @@ def _para(text: str) -> Paragraph:
|
|
|
81
81
|
return Paragraph(children=(TextNode(text),))
|
|
82
82
|
|
|
83
83
|
|
|
84
|
-
def
|
|
84
|
+
def test_expands_first_occurrence_as_footnote():
|
|
85
85
|
abbrevs = {"IAM": "Identity and Access Management"}
|
|
86
86
|
nodes = (_para("The IAM platform handles IAM requests."),)
|
|
87
87
|
result = apply_abbreviations(nodes, abbrevs, page_text="The IAM platform handles IAM requests.")
|
|
88
88
|
para = result[0]
|
|
89
89
|
assert isinstance(para, Paragraph)
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
assert
|
|
94
|
-
|
|
90
|
+
children = para.children
|
|
91
|
+
# TextNode("The ") + AbbrevFootnoteNode + TextNode(" platform handles IAM requests.")
|
|
92
|
+
assert len(children) == 3
|
|
93
|
+
assert isinstance(children[0], TextNode) and children[0].text == "The "
|
|
94
|
+
fn = children[1]
|
|
95
|
+
assert isinstance(fn, AbbrevFootnoteNode)
|
|
96
|
+
assert fn.abbr == "IAM"
|
|
97
|
+
assert fn.definition == "Identity and Access Management"
|
|
98
|
+
assert fn.number == 1
|
|
99
|
+
# Second occurrence left as plain text
|
|
100
|
+
assert isinstance(children[2], TextNode)
|
|
101
|
+
assert "IAM requests." in children[2].text
|
|
102
|
+
# Glossary block appended
|
|
103
|
+
glossary = result[1]
|
|
104
|
+
assert isinstance(glossary, AbbrevGlossaryBlock)
|
|
105
|
+
assert glossary.footnoted[0].abbr == "IAM"
|
|
106
|
+
assert glossary.footnoted[0].number == 1
|
|
95
107
|
|
|
96
108
|
|
|
97
109
|
def test_expands_multiple_different_abbrevs():
|
|
98
110
|
abbrevs = {"IAM": "Identity and Access Management", "RBAC": "Role-Based Access Control"}
|
|
99
111
|
nodes = (_para("Use IAM and RBAC for access control."),)
|
|
100
112
|
result = apply_abbreviations(nodes, abbrevs, page_text="Use IAM and RBAC for access control.")
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
113
|
+
para = result[0]
|
|
114
|
+
footnotes = [c for c in para.children if isinstance(c, AbbrevFootnoteNode)]
|
|
115
|
+
abbrs = {fn.abbr for fn in footnotes}
|
|
116
|
+
assert "IAM" in abbrs
|
|
117
|
+
assert "RBAC" in abbrs
|
|
118
|
+
numbers = sorted(fn.number for fn in footnotes)
|
|
119
|
+
assert numbers == [1, 2]
|
|
104
120
|
|
|
105
121
|
|
|
106
122
|
def test_no_expand_when_no_abbrevs():
|
|
@@ -111,173 +127,110 @@ def test_no_expand_when_no_abbrevs():
|
|
|
111
127
|
|
|
112
128
|
def test_no_expand_in_section_heading():
|
|
113
129
|
abbrevs = {"IAM": "Identity and Access Management"}
|
|
114
|
-
section = Section(
|
|
115
|
-
level=2,
|
|
116
|
-
anchor="iam",
|
|
117
|
-
title=(TextNode("IAM Platform"),),
|
|
118
|
-
children=(),
|
|
119
|
-
)
|
|
130
|
+
section = Section(level=2, anchor="iam", title=(TextNode("IAM Platform"),), children=())
|
|
120
131
|
result = apply_abbreviations((section,), abbrevs, page_text="IAM Platform")
|
|
121
132
|
heading_text = result[0].title[0].text # type: ignore[union-attr]
|
|
122
|
-
assert heading_text == "IAM Platform" # not
|
|
133
|
+
assert heading_text == "IAM Platform" # not annotated
|
|
123
134
|
|
|
124
135
|
|
|
125
|
-
def
|
|
136
|
+
def test_glossary_block_appended_for_heading_only_abbrev():
|
|
126
137
|
abbrevs = {"IAM": "Identity and Access Management"}
|
|
127
|
-
section = Section(
|
|
128
|
-
level=2,
|
|
129
|
-
anchor="iam",
|
|
130
|
-
title=(TextNode("IAM Platform"),),
|
|
131
|
-
children=(),
|
|
132
|
-
)
|
|
138
|
+
section = Section(level=2, anchor="iam", title=(TextNode("IAM Platform"),), children=())
|
|
133
139
|
result = apply_abbreviations((section,), abbrevs, page_text="IAM Platform")
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
assert isinstance(
|
|
137
|
-
glossary
|
|
138
|
-
assert
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
bullet_list = glossary.children[0]
|
|
143
|
-
assert isinstance(bullet_list, BulletList)
|
|
144
|
-
item_text = bullet_list.items[0].children[0].children[0].text # type: ignore[union-attr]
|
|
145
|
-
assert "IAM" in item_text
|
|
146
|
-
assert "Identity and Access Management" in item_text
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
def test_no_glossary_when_abbrev_expanded_inline():
|
|
140
|
+
assert len(result) == 2
|
|
141
|
+
glossary = result[1]
|
|
142
|
+
assert isinstance(glossary, AbbrevGlossaryBlock)
|
|
143
|
+
assert len(glossary.footnoted) == 0
|
|
144
|
+
assert glossary.extras == (("IAM", "Identity and Access Management"),)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def test_no_glossary_when_abbrev_footnoted_inline():
|
|
150
148
|
abbrevs = {"IAM": "Identity and Access Management"}
|
|
151
149
|
nodes = (_para("The IAM platform."),)
|
|
152
150
|
result = apply_abbreviations(nodes, abbrevs, page_text="The IAM platform.")
|
|
153
|
-
|
|
154
|
-
assert
|
|
155
|
-
assert
|
|
156
|
-
glossary = result[-1]
|
|
157
|
-
assert isinstance(glossary, Section)
|
|
158
|
-
assert glossary.anchor == "glossary"
|
|
151
|
+
assert len(result) == 2
|
|
152
|
+
assert isinstance(result[1], AbbrevGlossaryBlock)
|
|
153
|
+
assert len(result[1].extras) == 0
|
|
159
154
|
|
|
160
155
|
|
|
161
156
|
def test_no_expand_in_table_header_cell():
|
|
162
157
|
abbrevs = {"API": "Application Programming Interface"}
|
|
163
|
-
header = TableRow(cells=(
|
|
164
|
-
|
|
165
|
-
))
|
|
166
|
-
body = TableRow(cells=(
|
|
167
|
-
TableCell(children=(TextNode("The API docs"),), is_header=False),
|
|
168
|
-
))
|
|
158
|
+
header = TableRow(cells=(TableCell(children=(TextNode("API Endpoint"),), is_header=True),))
|
|
159
|
+
body = TableRow(cells=(TableCell(children=(TextNode("The API docs"),), is_header=False),))
|
|
169
160
|
table = Table(header=header, rows=(body,))
|
|
170
161
|
result = apply_abbreviations((table,), abbrevs, page_text="API Endpoint The API docs")
|
|
171
|
-
|
|
172
|
-
# Header cell: not expanded
|
|
173
162
|
header_text = result[0].header.cells[0].children[0].text # type: ignore[union-attr]
|
|
174
163
|
assert header_text == "API Endpoint"
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
body_text = result[0].rows[0].cells[0].children[0].text # type: ignore[union-attr]
|
|
178
|
-
assert "API (Application Programming Interface)" in body_text
|
|
164
|
+
body_children = result[0].rows[0].cells[0].children # type: ignore[union-attr]
|
|
165
|
+
assert any(isinstance(c, AbbrevFootnoteNode) and c.abbr == "API" for c in body_children)
|
|
179
166
|
|
|
180
167
|
|
|
181
168
|
def test_no_expand_in_admonition_title():
|
|
182
169
|
abbrevs = {"TLS": "Transport Layer Security"}
|
|
183
170
|
admonition = Admonition(
|
|
184
|
-
kind="note",
|
|
185
|
-
title="TLS Configuration",
|
|
171
|
+
kind="note", title="TLS Configuration",
|
|
186
172
|
children=(_para("Use TLS for encryption."),),
|
|
187
173
|
)
|
|
188
174
|
result = apply_abbreviations((admonition,), abbrevs, page_text="TLS Configuration Use TLS for encryption.")
|
|
189
|
-
# Title is str, unchanged
|
|
190
175
|
assert result[0].title == "TLS Configuration" # type: ignore[union-attr]
|
|
191
|
-
#
|
|
192
|
-
|
|
193
|
-
assert "TLS (Transport Layer Security)" in body_text
|
|
176
|
+
body_children = result[0].children[0].children # type: ignore[union-attr]
|
|
177
|
+
assert any(isinstance(c, AbbrevFootnoteNode) and c.abbr == "TLS" for c in body_children)
|
|
194
178
|
|
|
195
179
|
|
|
196
180
|
def test_no_expand_in_code_block():
|
|
197
181
|
abbrevs = {"SQL": "Structured Query Language"}
|
|
198
182
|
code = CodeBlock(code="SELECT * FROM SQL_table", language="sql")
|
|
199
|
-
|
|
200
|
-
result
|
|
201
|
-
assert result[0].code == "SELECT * FROM SQL_table"
|
|
183
|
+
result = apply_abbreviations((code,), abbrevs, page_text="SELECT * FROM SQL_table")
|
|
184
|
+
assert result[0].code == "SELECT * FROM SQL_table" # type: ignore[union-attr]
|
|
202
185
|
|
|
203
186
|
|
|
204
187
|
def test_no_expand_in_link_text():
|
|
205
188
|
abbrevs = {"CLI": "Command Line Interface"}
|
|
206
|
-
link = LinkNode(
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
)
|
|
210
|
-
para = Paragraph(children=(link,))
|
|
211
|
-
result = apply_abbreviations((para,), abbrevs, page_text="CLI tools")
|
|
212
|
-
link_text = result[0].children[0].children[0].text # type: ignore[union-attr]
|
|
213
|
-
assert link_text == "CLI tools" # not expanded inside link
|
|
189
|
+
link = LinkNode(href="https://example.com", children=(TextNode("CLI tools"),))
|
|
190
|
+
result = apply_abbreviations((Paragraph(children=(link,)),), abbrevs, page_text="CLI tools")
|
|
191
|
+
assert result[0].children[0].children[0].text == "CLI tools" # type: ignore[union-attr]
|
|
214
192
|
|
|
215
193
|
|
|
216
194
|
def test_expands_inside_bold():
|
|
217
195
|
abbrevs = {"CI": "Continuous Integration"}
|
|
218
196
|
bold = BoldNode(children=(TextNode("CI pipeline"),))
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
assert "CI (Continuous Integration)" in bold_text
|
|
197
|
+
result = apply_abbreviations((Paragraph(children=(bold,)),), abbrevs, page_text="CI pipeline")
|
|
198
|
+
bold_children = result[0].children[0].children # type: ignore[union-attr]
|
|
199
|
+
assert any(isinstance(c, AbbrevFootnoteNode) and c.abbr == "CI" for c in bold_children)
|
|
223
200
|
|
|
224
201
|
|
|
225
202
|
def test_word_boundary_not_partial_match():
|
|
226
203
|
abbrevs = {"API": "Application Programming Interface"}
|
|
227
204
|
nodes = (_para("The RAPID response via API."),)
|
|
228
205
|
result = apply_abbreviations(nodes, abbrevs, page_text="The RAPID response via API.")
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
assert "RAPID" in
|
|
232
|
-
assert "API
|
|
206
|
+
para = result[0]
|
|
207
|
+
all_text = "".join(c.text for c in para.children if isinstance(c, TextNode))
|
|
208
|
+
assert "RAPID" in all_text
|
|
209
|
+
assert any(isinstance(c, AbbrevFootnoteNode) and c.abbr == "API" for c in para.children)
|
|
233
210
|
|
|
234
211
|
|
|
235
|
-
def
|
|
236
|
-
# Abbreviations expanded inline should ALSO appear in the glossary,
|
|
237
|
-
# so readers who jump directly to the bottom have a full reference.
|
|
212
|
+
def test_footnoted_abbrevs_not_in_extras():
|
|
238
213
|
abbrevs = {"API": "Application Programming Interface", "IAM": "Identity and Access Management"}
|
|
239
214
|
nodes = (_para("Use the API and IAM to authenticate."),)
|
|
240
|
-
result = apply_abbreviations(
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
)
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
assert "API (Application Programming Interface)" in body_text
|
|
247
|
-
assert "IAM (Identity and Access Management)" in body_text
|
|
248
|
-
# ...AND both should appear in the glossary at the bottom.
|
|
249
|
-
assert len(result) == 3
|
|
250
|
-
assert isinstance(result[1], HorizontalRule)
|
|
251
|
-
glossary = result[-1]
|
|
252
|
-
assert isinstance(glossary, Section)
|
|
253
|
-
items = glossary.children[0].items # type: ignore[union-attr]
|
|
254
|
-
labels = " ".join(item.children[0].children[0].text for item in items) # type: ignore[union-attr]
|
|
255
|
-
assert "API" in labels
|
|
256
|
-
assert "IAM" in labels
|
|
215
|
+
result = apply_abbreviations(nodes, abbrevs, page_text="Use the API and IAM to authenticate.")
|
|
216
|
+
assert len(result) == 2
|
|
217
|
+
glossary = result[1]
|
|
218
|
+
assert isinstance(glossary, AbbrevGlossaryBlock)
|
|
219
|
+
assert {fn.abbr for fn in glossary.footnoted} == {"API", "IAM"}
|
|
220
|
+
assert len(glossary.extras) == 0
|
|
257
221
|
|
|
258
222
|
|
|
259
223
|
def test_abbrev_not_in_text_produces_no_glossary():
|
|
260
224
|
abbrevs = {"XYZ": "Some Definition"}
|
|
261
|
-
|
|
262
|
-
result = apply_abbreviations(nodes, abbrevs, page_text="Nothing relevant here.")
|
|
263
|
-
# XYZ never mentioned → no glossary
|
|
225
|
+
result = apply_abbreviations((_para("Nothing relevant here."),), abbrevs, page_text="Nothing relevant here.")
|
|
264
226
|
assert len(result) == 1
|
|
265
227
|
|
|
266
228
|
|
|
267
|
-
def
|
|
229
|
+
def test_extras_sorted_alphabetically():
|
|
268
230
|
abbrevs = {"RBAC": "Role-Based Access Control", "IAM": "Identity and Access Management"}
|
|
269
|
-
|
|
270
|
-
section =
|
|
271
|
-
level=1,
|
|
272
|
-
anchor="overview",
|
|
273
|
-
title=(TextNode("IAM and RBAC Overview"),),
|
|
274
|
-
children=(),
|
|
275
|
-
)
|
|
276
|
-
result = apply_abbreviations(
|
|
277
|
-
(section,), abbrevs, page_text="IAM and RBAC Overview"
|
|
278
|
-
)
|
|
231
|
+
section = Section(level=1, anchor="overview", title=(TextNode("IAM and RBAC Overview"),), children=())
|
|
232
|
+
result = apply_abbreviations((section,), abbrevs, page_text="IAM and RBAC Overview")
|
|
279
233
|
glossary = result[-1]
|
|
280
|
-
assert isinstance(glossary,
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
assert labels == sorted(labels)
|
|
234
|
+
assert isinstance(glossary, AbbrevGlossaryBlock)
|
|
235
|
+
extra_abbrs = [abbr for abbr, _ in glossary.extras]
|
|
236
|
+
assert extra_abbrs == sorted(extra_abbrs)
|
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs2confluence.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs2confluence.egg-info/entry_points.txt
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs2confluence.egg-info/requires.txt
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs2confluence.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/emitter/__init__.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/ir/__init__.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/ir/document.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/ir/treeutil.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/loader/__init__.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/loader/config.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/loader/extra_css.py
RENAMED
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/loader/page.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/parser/__init__.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/parser/markdown.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/pdf/__init__.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/pdf/generator.py
RENAMED
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/preprocess/__init__.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/preprocess/abbrevs.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/preprocess/fence.py
RENAMED
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/preprocess/icons.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/preprocess/includes.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/preprocess/linkdefs.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/preview/__init__.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/preview/render.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/preview/server.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/publisher/__init__.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/publisher/client.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/publisher/pipeline.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/transforms/__init__.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/transforms/assets.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/transforms/editlink.py
RENAMED
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/src/mkdocs_to_confluence/transforms/images.py
RENAMED
|
File without changes
|
|
File without changes
|
{mkdocs2confluence-0.7.9 → mkdocs2confluence-0.7.11}/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
|
|
File without changes
|
|
File without changes
|