markdown2jira 0.0.1__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.
- markdown2jira-0.0.1/PKG-INFO +33 -0
- markdown2jira-0.0.1/README.md +19 -0
- markdown2jira-0.0.1/pyproject.toml +122 -0
- markdown2jira-0.0.1/pyproject.toml.orig +106 -0
- markdown2jira-0.0.1/src/markdown2jira/__init__.py +12 -0
- markdown2jira-0.0.1/src/markdown2jira/_convert.py +55 -0
- markdown2jira-0.0.1/src/markdown2jira/_renderer.py +208 -0
- markdown2jira-0.0.1/src/markdown2jira/py.typed +1 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: markdown2jira
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Convert Markdown to Jira wiki markup
|
|
5
|
+
Keywords: markdown,jira,wiki markup,confluence
|
|
6
|
+
Author: Abraham Murciano
|
|
7
|
+
Author-email: Abraham Murciano <abrahammurciano@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Requires-Dist: wenmode>=0.15.1
|
|
10
|
+
Requires-Python: >=3.14
|
|
11
|
+
Project-URL: repository, https://github.com/abrahammurciano/python-markdown2jira
|
|
12
|
+
Project-URL: documentation, https://abrahammurciano.github.io/python-markdown2jira/markdown2jira
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
|
|
15
|
+
# markdown2jira
|
|
16
|
+
Convert Markdown to Jira wiki markup
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
You can install this package with pip.
|
|
21
|
+
```sh
|
|
22
|
+
$ pip install markdown2jira
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Links
|
|
26
|
+
|
|
27
|
+
[](https://abrahammurciano.github.io/python-markdown2jira)
|
|
28
|
+
|
|
29
|
+
[](https://github.com/abrahammurciano/python-markdown2jira.git)
|
|
30
|
+
|
|
31
|
+
[](https://pypi.org/project/markdown2jira/)
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# markdown2jira
|
|
2
|
+
Convert Markdown to Jira wiki markup
|
|
3
|
+
|
|
4
|
+
## Installation
|
|
5
|
+
|
|
6
|
+
You can install this package with pip.
|
|
7
|
+
```sh
|
|
8
|
+
$ pip install markdown2jira
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Links
|
|
12
|
+
|
|
13
|
+
[](https://abrahammurciano.github.io/python-markdown2jira)
|
|
14
|
+
|
|
15
|
+
[](https://github.com/abrahammurciano/python-markdown2jira.git)
|
|
16
|
+
|
|
17
|
+
[](https://pypi.org/project/markdown2jira/)
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "markdown2jira"
|
|
3
|
+
version = "0.0.1"
|
|
4
|
+
description = "Convert Markdown to Jira wiki markup"
|
|
5
|
+
license = "MIT"
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
requires-python = ">=3.14"
|
|
8
|
+
keywords = [
|
|
9
|
+
"markdown",
|
|
10
|
+
"jira",
|
|
11
|
+
"wiki markup",
|
|
12
|
+
"confluence",
|
|
13
|
+
]
|
|
14
|
+
dependencies = ["wenmode>=0.15.1"]
|
|
15
|
+
|
|
16
|
+
[[project.authors]]
|
|
17
|
+
name = "Abraham Murciano"
|
|
18
|
+
email = "abrahammurciano@gmail.com"
|
|
19
|
+
|
|
20
|
+
[project.urls]
|
|
21
|
+
repository = "https://github.com/abrahammurciano/python-markdown2jira"
|
|
22
|
+
documentation = "https://abrahammurciano.github.io/python-markdown2jira/markdown2jira"
|
|
23
|
+
|
|
24
|
+
[dependency-groups]
|
|
25
|
+
dev = [
|
|
26
|
+
"basedpyright",
|
|
27
|
+
"mypy",
|
|
28
|
+
"pdoc3",
|
|
29
|
+
"pytest",
|
|
30
|
+
"ruff",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[build-system]
|
|
34
|
+
requires = ["uv_build>=0.12,<0.13"]
|
|
35
|
+
build-backend = "uv_build"
|
|
36
|
+
|
|
37
|
+
[tool.uv.build-backend]
|
|
38
|
+
module-name = ["markdown2jira"]
|
|
39
|
+
|
|
40
|
+
[tool.mypy]
|
|
41
|
+
exclude = [
|
|
42
|
+
".venv",
|
|
43
|
+
"venv",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
[tool.basedpyright]
|
|
47
|
+
reportUnusedCallResult = "none"
|
|
48
|
+
reportAny = "none"
|
|
49
|
+
reportIncompatibleUnannotatedOverride = "warning"
|
|
50
|
+
reportUnannotatedClassAttribute = "none"
|
|
51
|
+
reportUnusedParameter = "none"
|
|
52
|
+
reportCallInDefaultInitializer = "none"
|
|
53
|
+
reportExplicitAny = "none"
|
|
54
|
+
reportInvalidCast = "none"
|
|
55
|
+
reportUnknownLambdaType = "none"
|
|
56
|
+
reportImportCycles = "hint"
|
|
57
|
+
|
|
58
|
+
[tool.ruff.lint]
|
|
59
|
+
select = ["ALL"]
|
|
60
|
+
ignore = [
|
|
61
|
+
"A001",
|
|
62
|
+
"A002",
|
|
63
|
+
"ANN401",
|
|
64
|
+
"C901",
|
|
65
|
+
"COM812",
|
|
66
|
+
"CPY001",
|
|
67
|
+
"D100",
|
|
68
|
+
"D101",
|
|
69
|
+
"D102",
|
|
70
|
+
"D103",
|
|
71
|
+
"D104",
|
|
72
|
+
"D105",
|
|
73
|
+
"D106",
|
|
74
|
+
"D107",
|
|
75
|
+
"D203",
|
|
76
|
+
"D213",
|
|
77
|
+
"D413",
|
|
78
|
+
"E501",
|
|
79
|
+
"EM101",
|
|
80
|
+
"EM102",
|
|
81
|
+
"G004",
|
|
82
|
+
"PLC0415",
|
|
83
|
+
"PLR0911",
|
|
84
|
+
"PLR0912",
|
|
85
|
+
"PLR0913",
|
|
86
|
+
"PLR2004",
|
|
87
|
+
"PT013",
|
|
88
|
+
"PYI025",
|
|
89
|
+
"S101",
|
|
90
|
+
"S104",
|
|
91
|
+
"S105",
|
|
92
|
+
"S311",
|
|
93
|
+
"S603",
|
|
94
|
+
"S608",
|
|
95
|
+
"TC001",
|
|
96
|
+
"TC002",
|
|
97
|
+
"TC003",
|
|
98
|
+
"TC006",
|
|
99
|
+
"TD002",
|
|
100
|
+
"TD003",
|
|
101
|
+
"TRY003",
|
|
102
|
+
"TRY400",
|
|
103
|
+
]
|
|
104
|
+
|
|
105
|
+
[tool.ruff.lint.flake8-annotations]
|
|
106
|
+
allow-star-arg-any = true
|
|
107
|
+
|
|
108
|
+
[tool.ruff.lint.flake8-pytest-style]
|
|
109
|
+
parametrize-values-type = "tuple"
|
|
110
|
+
parametrize-values-row-type = "tuple"
|
|
111
|
+
|
|
112
|
+
[tool.ruff.lint.pylint]
|
|
113
|
+
max-args = 10
|
|
114
|
+
|
|
115
|
+
[tool.ruff.lint.per-file-ignores]
|
|
116
|
+
"tests/**.py" = ["ARG001"]
|
|
117
|
+
|
|
118
|
+
[tool.ruff.lint.isort]
|
|
119
|
+
split-on-trailing-comma = false
|
|
120
|
+
|
|
121
|
+
[tool.ruff.format]
|
|
122
|
+
skip-magic-trailing-comma = true
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "markdown2jira"
|
|
3
|
+
# Version is overwritten at build time by CI based on git tag
|
|
4
|
+
version = "0.0.1"
|
|
5
|
+
description = "Convert Markdown to Jira wiki markup"
|
|
6
|
+
authors = [{ name = "Abraham Murciano", email = "abrahammurciano@gmail.com" }]
|
|
7
|
+
license = "MIT"
|
|
8
|
+
readme = "README.md"
|
|
9
|
+
requires-python = ">=3.14"
|
|
10
|
+
keywords = ["markdown", "jira", "wiki markup", "confluence"]
|
|
11
|
+
dependencies = ["wenmode>=0.15.1"]
|
|
12
|
+
|
|
13
|
+
[project.urls]
|
|
14
|
+
repository = "https://github.com/abrahammurciano/python-markdown2jira"
|
|
15
|
+
documentation = "https://abrahammurciano.github.io/python-markdown2jira/markdown2jira"
|
|
16
|
+
|
|
17
|
+
[dependency-groups]
|
|
18
|
+
dev = ["basedpyright", "mypy", "pdoc3", "pytest", "ruff"]
|
|
19
|
+
|
|
20
|
+
[build-system]
|
|
21
|
+
requires = ["uv_build>=0.12,<0.13"]
|
|
22
|
+
build-backend = "uv_build"
|
|
23
|
+
|
|
24
|
+
[tool.uv.build-backend]
|
|
25
|
+
module-name = ["markdown2jira"]
|
|
26
|
+
|
|
27
|
+
[tool.mypy]
|
|
28
|
+
exclude = [".venv", "venv"]
|
|
29
|
+
|
|
30
|
+
[tool.basedpyright]
|
|
31
|
+
reportUnusedCallResult = "none"
|
|
32
|
+
reportAny = "none"
|
|
33
|
+
reportIncompatibleUnannotatedOverride = "warning"
|
|
34
|
+
reportUnannotatedClassAttribute = "none"
|
|
35
|
+
reportUnusedParameter = "none"
|
|
36
|
+
reportCallInDefaultInitializer = "none"
|
|
37
|
+
reportExplicitAny = "none"
|
|
38
|
+
reportInvalidCast = "none"
|
|
39
|
+
reportUnknownLambdaType = "none"
|
|
40
|
+
reportImportCycles = "hint"
|
|
41
|
+
|
|
42
|
+
[tool.ruff.lint]
|
|
43
|
+
select = ["ALL"]
|
|
44
|
+
ignore = [
|
|
45
|
+
"A001",
|
|
46
|
+
"A002",
|
|
47
|
+
"ANN401",
|
|
48
|
+
"C901",
|
|
49
|
+
"COM812",
|
|
50
|
+
"CPY001",
|
|
51
|
+
"D100",
|
|
52
|
+
"D101",
|
|
53
|
+
"D102",
|
|
54
|
+
"D103",
|
|
55
|
+
"D104",
|
|
56
|
+
"D105",
|
|
57
|
+
"D106",
|
|
58
|
+
"D107",
|
|
59
|
+
"D203",
|
|
60
|
+
"D213",
|
|
61
|
+
"D413",
|
|
62
|
+
"E501",
|
|
63
|
+
"EM101",
|
|
64
|
+
"EM102",
|
|
65
|
+
"G004",
|
|
66
|
+
"PLC0415",
|
|
67
|
+
"PLR0911",
|
|
68
|
+
"PLR0912",
|
|
69
|
+
"PLR0913",
|
|
70
|
+
"PLR2004",
|
|
71
|
+
"PT013",
|
|
72
|
+
"PYI025",
|
|
73
|
+
"S101",
|
|
74
|
+
"S104",
|
|
75
|
+
"S105",
|
|
76
|
+
"S311",
|
|
77
|
+
"S603",
|
|
78
|
+
"S608",
|
|
79
|
+
"TC001",
|
|
80
|
+
"TC002",
|
|
81
|
+
"TC003",
|
|
82
|
+
"TC006",
|
|
83
|
+
"TD002",
|
|
84
|
+
"TD003",
|
|
85
|
+
"TRY003",
|
|
86
|
+
"TRY400",
|
|
87
|
+
]
|
|
88
|
+
|
|
89
|
+
[tool.ruff.lint.flake8-annotations]
|
|
90
|
+
allow-star-arg-any = true
|
|
91
|
+
|
|
92
|
+
[tool.ruff.lint.flake8-pytest-style]
|
|
93
|
+
parametrize-values-type = "tuple"
|
|
94
|
+
parametrize-values-row-type = "tuple"
|
|
95
|
+
|
|
96
|
+
[tool.ruff.lint.pylint]
|
|
97
|
+
max-args = 10
|
|
98
|
+
|
|
99
|
+
[tool.ruff.lint.per-file-ignores]
|
|
100
|
+
"tests/**.py" = ["ARG001"]
|
|
101
|
+
|
|
102
|
+
[tool.ruff.lint.isort]
|
|
103
|
+
split-on-trailing-comma = false
|
|
104
|
+
|
|
105
|
+
[tool.ruff.format]
|
|
106
|
+
skip-magic-trailing-comma = true
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"""Convert Markdown to Jira wiki markup.
|
|
2
|
+
|
|
3
|
+
.. include:: ../../README.md
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from importlib import metadata
|
|
7
|
+
|
|
8
|
+
from ._convert import Markdown2Jira, convert
|
|
9
|
+
from ._renderer import JiraRenderContext, JiraRenderer
|
|
10
|
+
|
|
11
|
+
__version__ = metadata.version(__package__ or __name__)
|
|
12
|
+
__all__ = ["JiraRenderContext", "JiraRenderer", "Markdown2Jira", "convert"]
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
from collections.abc import Iterable
|
|
2
|
+
from types import ModuleType
|
|
3
|
+
|
|
4
|
+
from wenmode import Wenmode
|
|
5
|
+
from wenmode.plugins import PluginModule
|
|
6
|
+
from wenmode.presets import PresetFactory, github
|
|
7
|
+
from wenmode.renderers import BaseRenderer
|
|
8
|
+
from wenmode.rules import Rule
|
|
9
|
+
|
|
10
|
+
from ._renderer import JiraRenderer
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Markdown2Jira:
|
|
14
|
+
"""Converts Markdown to Jira wiki markup, with configurable parsing rules and rendering.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
rules: The Markdown parsing rules to use. Defaults to the GitHub preset (tables, task lists, strikethrough, auto-links, footnotes).
|
|
18
|
+
renderer: The renderer used to turn the parsed Markdown into Jira wiki markup. Defaults to `JiraRenderer`. Subclass `JiraRenderer` to support custom node types.
|
|
19
|
+
plugins: Wenmode plugins to extend parsing with, e.g. for custom syntax.
|
|
20
|
+
positions: Whether to track source positions on parsed nodes.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
rules: Iterable[type[Rule] | Rule] | PresetFactory | None = None,
|
|
26
|
+
*,
|
|
27
|
+
renderer: BaseRenderer | None = None,
|
|
28
|
+
plugins: Iterable[PluginModule | ModuleType] = (),
|
|
29
|
+
positions: bool = False,
|
|
30
|
+
) -> None:
|
|
31
|
+
self._wenmode = Wenmode(
|
|
32
|
+
rules if rules is not None else github(),
|
|
33
|
+
renderer=renderer or JiraRenderer(),
|
|
34
|
+
plugins=plugins,
|
|
35
|
+
positions=positions,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
def convert(self, content: str) -> str:
|
|
39
|
+
"""Convert a Markdown string to Jira wiki markup."""
|
|
40
|
+
return self._wenmode.render(content).strip("\n")
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
_default = Markdown2Jira()
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def convert(content: str) -> str:
|
|
47
|
+
"""Convert a Markdown string to Jira wiki markup, using the default rules and renderer.
|
|
48
|
+
|
|
49
|
+
Args:
|
|
50
|
+
content: The Markdown source to convert.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
The equivalent Jira wiki markup.
|
|
54
|
+
"""
|
|
55
|
+
return _default.convert(content)
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
|
+
from typing import override
|
|
3
|
+
|
|
4
|
+
from wenmode.nodes import (
|
|
5
|
+
Blockquote,
|
|
6
|
+
Break,
|
|
7
|
+
Code,
|
|
8
|
+
Delete,
|
|
9
|
+
Emphasis,
|
|
10
|
+
Heading,
|
|
11
|
+
Html,
|
|
12
|
+
Image,
|
|
13
|
+
InlineCode,
|
|
14
|
+
Link,
|
|
15
|
+
List,
|
|
16
|
+
ListItem,
|
|
17
|
+
Node,
|
|
18
|
+
Paragraph,
|
|
19
|
+
Strong,
|
|
20
|
+
Table,
|
|
21
|
+
TableCell,
|
|
22
|
+
TableRow,
|
|
23
|
+
Text,
|
|
24
|
+
ThematicBreak,
|
|
25
|
+
)
|
|
26
|
+
from wenmode.renderers import BaseRenderer, RenderContext
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass
|
|
30
|
+
class JiraRenderContext(RenderContext):
|
|
31
|
+
list_markers: list[str] = field(default_factory=list)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class JiraRenderer(BaseRenderer):
|
|
35
|
+
name = "jira"
|
|
36
|
+
|
|
37
|
+
@override
|
|
38
|
+
def create_context(self, node: Node | None = None) -> JiraRenderContext:
|
|
39
|
+
return JiraRenderContext()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@JiraRenderer.register("paragraph")
|
|
43
|
+
def render_paragraph(
|
|
44
|
+
renderer: JiraRenderer, node: Paragraph, context: JiraRenderContext
|
|
45
|
+
) -> str:
|
|
46
|
+
return renderer.render_children(node.children, context) + "\n\n"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@JiraRenderer.register("heading")
|
|
50
|
+
def render_heading(
|
|
51
|
+
renderer: JiraRenderer, node: Heading, context: JiraRenderContext
|
|
52
|
+
) -> str:
|
|
53
|
+
depth = min(max(node.depth, 1), 6)
|
|
54
|
+
title = renderer.render_children(node.children, context)
|
|
55
|
+
return f"h{depth}. {title}\n\n"
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@JiraRenderer.register("blockquote")
|
|
59
|
+
def render_blockquote(
|
|
60
|
+
renderer: JiraRenderer, node: Blockquote, context: JiraRenderContext
|
|
61
|
+
) -> str:
|
|
62
|
+
body = renderer.render_children(node.children, context).rstrip("\n")
|
|
63
|
+
return f"{{quote}}\n{body}\n{{quote}}\n\n"
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@JiraRenderer.register("thematicBreak")
|
|
67
|
+
def render_thematic_break(
|
|
68
|
+
_renderer: JiraRenderer, _node: ThematicBreak, _context: JiraRenderContext
|
|
69
|
+
) -> str:
|
|
70
|
+
return "----\n\n"
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@JiraRenderer.register("html")
|
|
74
|
+
def render_html(
|
|
75
|
+
_renderer: JiraRenderer, node: Html, _context: JiraRenderContext
|
|
76
|
+
) -> str:
|
|
77
|
+
value = node.value.rstrip("\n")
|
|
78
|
+
return f"{{noformat}}\n{value}\n{{noformat}}\n\n"
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@JiraRenderer.register("text")
|
|
82
|
+
def render_text(
|
|
83
|
+
_renderer: JiraRenderer, node: Text, _context: JiraRenderContext
|
|
84
|
+
) -> str:
|
|
85
|
+
return node.value
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
@JiraRenderer.register("inlineCode")
|
|
89
|
+
def render_inline_code(
|
|
90
|
+
_renderer: JiraRenderer, node: InlineCode, _context: JiraRenderContext
|
|
91
|
+
) -> str:
|
|
92
|
+
return "{{" + node.value + "}}"
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@JiraRenderer.register("strong")
|
|
96
|
+
def render_strong(
|
|
97
|
+
renderer: JiraRenderer, node: Strong, context: JiraRenderContext
|
|
98
|
+
) -> str:
|
|
99
|
+
return "*" + renderer.render_children(node.children, context) + "*"
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@JiraRenderer.register("emphasis")
|
|
103
|
+
def render_emphasis(
|
|
104
|
+
renderer: JiraRenderer, node: Emphasis, context: JiraRenderContext
|
|
105
|
+
) -> str:
|
|
106
|
+
return "_" + renderer.render_children(node.children, context) + "_"
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@JiraRenderer.register("delete")
|
|
110
|
+
def render_delete(
|
|
111
|
+
renderer: JiraRenderer, node: Delete, context: JiraRenderContext
|
|
112
|
+
) -> str:
|
|
113
|
+
return "-" + renderer.render_children(node.children, context) + "-"
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@JiraRenderer.register("link")
|
|
117
|
+
def render_link(renderer: JiraRenderer, node: Link, context: JiraRenderContext) -> str:
|
|
118
|
+
text = renderer.render_children(node.children, context)
|
|
119
|
+
if node.title:
|
|
120
|
+
return f"[{text}|{node.url}|{node.title}]"
|
|
121
|
+
return f"[{text}|{node.url}]"
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
@JiraRenderer.register("image")
|
|
125
|
+
def render_image(
|
|
126
|
+
_renderer: JiraRenderer, node: Image, _context: JiraRenderContext
|
|
127
|
+
) -> str:
|
|
128
|
+
if node.alt:
|
|
129
|
+
return f"!{node.url}|alt={node.alt}!"
|
|
130
|
+
return f"!{node.url}!"
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@JiraRenderer.register("break")
|
|
134
|
+
def render_break(
|
|
135
|
+
_renderer: JiraRenderer, _node: Break, _context: JiraRenderContext
|
|
136
|
+
) -> str:
|
|
137
|
+
return "\\\\\n"
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
@JiraRenderer.register("code")
|
|
141
|
+
def render_code(
|
|
142
|
+
_renderer: JiraRenderer, node: Code, _context: JiraRenderContext
|
|
143
|
+
) -> str:
|
|
144
|
+
header = f"{{code:{node.lang}}}" if node.lang else "{code}"
|
|
145
|
+
code = node.value if node.value.endswith("\n") else node.value + "\n"
|
|
146
|
+
return f"{header}\n{code}{{code}}\n\n"
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
@JiraRenderer.register("list")
|
|
150
|
+
def render_list(renderer: JiraRenderer, node: List, context: JiraRenderContext) -> str:
|
|
151
|
+
context.list_markers.append("#" if node.ordered else "*")
|
|
152
|
+
text = renderer.render_children(node.children, context)
|
|
153
|
+
context.list_markers.pop()
|
|
154
|
+
return text if context.list_markers else text + "\n"
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
@JiraRenderer.register("listItem")
|
|
158
|
+
def render_list_item(
|
|
159
|
+
renderer: JiraRenderer, node: ListItem, context: JiraRenderContext
|
|
160
|
+
) -> str:
|
|
161
|
+
marker = "".join(context.list_markers)
|
|
162
|
+
if node.checked is not None:
|
|
163
|
+
marker += " [x]" if node.checked else " [ ]"
|
|
164
|
+
parts: list[str] = []
|
|
165
|
+
for child in node.children:
|
|
166
|
+
if isinstance(child, List):
|
|
167
|
+
parts.append(renderer.render_node(child, context))
|
|
168
|
+
else:
|
|
169
|
+
text = renderer.render_node(child, context).rstrip("\n")
|
|
170
|
+
parts.append(f"{marker} {text}\n")
|
|
171
|
+
return "".join(parts)
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
@JiraRenderer.register("table")
|
|
175
|
+
def render_table(
|
|
176
|
+
renderer: JiraRenderer, node: Table, context: JiraRenderContext
|
|
177
|
+
) -> str:
|
|
178
|
+
rows = [child for child in node.children if isinstance(child, TableRow)]
|
|
179
|
+
if not rows:
|
|
180
|
+
return ""
|
|
181
|
+
head, *body = rows
|
|
182
|
+
lines = [render_table_head(renderer, head, context)]
|
|
183
|
+
lines.extend(render_table_row(renderer, row, context) for row in body)
|
|
184
|
+
return "".join(lines) + "\n"
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def table_row_cells(row: TableRow) -> list[TableCell]:
|
|
188
|
+
return [cell for cell in row.children if isinstance(cell, TableCell)]
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def render_table_head(
|
|
192
|
+
renderer: JiraRenderer, row: TableRow, context: JiraRenderContext
|
|
193
|
+
) -> str:
|
|
194
|
+
cells = "".join(
|
|
195
|
+
"||" + renderer.render_children(cell.children, context)
|
|
196
|
+
for cell in table_row_cells(row)
|
|
197
|
+
)
|
|
198
|
+
return cells + "||\n"
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def render_table_row(
|
|
202
|
+
renderer: JiraRenderer, row: TableRow, context: JiraRenderContext
|
|
203
|
+
) -> str:
|
|
204
|
+
cells = "".join(
|
|
205
|
+
"|" + renderer.render_children(cell.children, context)
|
|
206
|
+
for cell in table_row_cells(row)
|
|
207
|
+
)
|
|
208
|
+
return cells + "|\n"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|