From b8f92f662438acc3734ce1179e224d83c7a9cf98 Mon Sep 17 00:00:00 2001 From: Levente Hunyadi Date: Tue, 10 Sep 2024 23:17:54 +0200 Subject: [PATCH] Add support for GitHub syntax of alerts/admonitions --- md2conf/converter.py | 59 ++++++++++++++++++++++++++++++++++++++++++ tests/source/alert.md | 28 ++++++++++++++++++++ tests/target/alert.xml | 36 ++++++++++++++++++++++++++ 3 files changed, 123 insertions(+) create mode 100644 tests/source/alert.md create mode 100644 tests/target/alert.xml diff --git a/md2conf/converter.py b/md2conf/converter.py index e5cd42e..ba07229 100644 --- a/md2conf/converter.py +++ b/md2conf/converter.py @@ -503,6 +503,52 @@ def _transform_admonition(self, elem: ET._Element) -> ET._Element: *content, ) + def _transform_alert(self, elem: ET._Element) -> ET._Element: + """ + Creates an info, tip, note or warning panel from a GitHub alert. + + Transforms + [GitHub alert](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#alerts) # noqa: E501 # no way to make this link shorter + syntax into one of the Confluence structured macros *info*, *tip*, *note*, or *warning*. + """ + + pattern = re.compile(r"^\[!([A-Z]+)\]\s*") + + content = elem[0] + if content.text is None: + raise DocumentError("empty content") + + match = pattern.match(content.text) + if match is None: + raise DocumentError("not an alert") + alert = match.group(1) + + if alert == "NOTE": + class_name = "note" + elif alert == "TIP": + class_name = "tip" + elif alert == "IMPORTANT": + class_name = "tip" + elif alert == "WARNING": + class_name = "warning" + elif alert == "CAUTION": + class_name = "warning" + else: + raise DocumentError(f"unsupported alert: {alert}") + + for e in elem: + self.visit(e) + + content.text = pattern.sub("", content.text, count=1) + return AC( + "structured-macro", + { + ET.QName(namespaces["ac"], "name"): class_name, + ET.QName(namespaces["ac"], "schema-version"): "1", + }, + AC("rich-text-body", {}, *list(elem)), + ) + def _transform_section(self, elem: ET._Element) -> ET._Element: """ Creates a collapsed section. @@ -569,6 +615,19 @@ def transform(self, child: ET._Element) -> Optional[ET._Element]: elif child.tag == "div" and "admonition" in child.attrib.get("class", ""): return self._transform_admonition(child) + # Alerts in GitHub + #
+ #

[!TIP] ...

+ #
+ elif ( + child.tag == "blockquote" + and len(child) > 0 + and child[0].tag == "p" + and child[0].text is not None + and child[0].text.startswith("[!") + ): + return self._transform_alert(child) + #
# ... # ... diff --git a/tests/source/alert.md b/tests/source/alert.md new file mode 100644 index 0000000..c466eff --- /dev/null +++ b/tests/source/alert.md @@ -0,0 +1,28 @@ + + +## Alerts + +Note: + +> [!NOTE] +> Useful information that users should know, even when skimming content. + +Tip: + +> [!TIP] +> Helpful advice for doing things better or more easily. + +Important: + +> [!IMPORTANT] +> Key information users need to know to achieve their goal. + +Warning: + +> [!WARNING] +> Urgent info that needs immediate user attention to avoid problems. + +Caution: + +> [!CAUTION] +> Advises about risks or negative outcomes of certain actions. diff --git a/tests/target/alert.xml b/tests/target/alert.xml new file mode 100644 index 0000000..782cc67 --- /dev/null +++ b/tests/target/alert.xml @@ -0,0 +1,36 @@ + + +

This page has been generated with a tool.

+
+
+

Alerts

+

Note:

+ + +

Useful information that users should know, even when skimming content.

+
+
+

Tip:

+ + +

Helpful advice for doing things better or more easily.

+
+
+

Important:

+ + +

Key information users need to know to achieve their goal.

+
+
+

Warning:

+ + +

Urgent info that needs immediate user attention to avoid problems.

+
+
+

Caution:

+ + +

Advises about risks or negative outcomes of certain actions.

+
+