markdownpal 0.1.0__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.
- markdownpal-0.1.0/.claude/settings.local.json +14 -0
- markdownpal-0.1.0/.gitignore +8 -0
- markdownpal-0.1.0/EXAMPLES.md +201 -0
- markdownpal-0.1.0/LICENSE +21 -0
- markdownpal-0.1.0/PKG-INFO +261 -0
- markdownpal-0.1.0/README.md +216 -0
- markdownpal-0.1.0/docs/superpowers/plans/2026-04-12-markdownpal.md +1035 -0
- markdownpal-0.1.0/docs/superpowers/specs/2026-04-12-markdownpal-design.md +195 -0
- markdownpal-0.1.0/main.py +22 -0
- markdownpal-0.1.0/markdownpal/__init__.py +23 -0
- markdownpal-0.1.0/markdownpal/blocks/__init__.py +17 -0
- markdownpal-0.1.0/markdownpal/blocks/base.py +8 -0
- markdownpal-0.1.0/markdownpal/blocks/code.py +10 -0
- markdownpal-0.1.0/markdownpal/blocks/heading.py +49 -0
- markdownpal-0.1.0/markdownpal/blocks/list_.py +30 -0
- markdownpal-0.1.0/markdownpal/blocks/media.py +19 -0
- markdownpal-0.1.0/markdownpal/blocks/table.py +21 -0
- markdownpal-0.1.0/markdownpal/blocks/text.py +30 -0
- markdownpal-0.1.0/markdownpal/document.py +18 -0
- markdownpal-0.1.0/markdownpal/inline.py +14 -0
- markdownpal-0.1.0/pyproject.toml +38 -0
- markdownpal-0.1.0/tests/__init__.py +0 -0
- markdownpal-0.1.0/tests/blocks/__init__.py +0 -0
- markdownpal-0.1.0/tests/blocks/test_code.py +17 -0
- markdownpal-0.1.0/tests/blocks/test_heading.py +29 -0
- markdownpal-0.1.0/tests/blocks/test_list.py +29 -0
- markdownpal-0.1.0/tests/blocks/test_media.py +17 -0
- markdownpal-0.1.0/tests/blocks/test_table.py +36 -0
- markdownpal-0.1.0/tests/blocks/test_text.py +25 -0
- markdownpal-0.1.0/tests/test_document.py +51 -0
- markdownpal-0.1.0/tests/test_inline.py +25 -0
- markdownpal-0.1.0/tests/test_integration.py +48 -0
- markdownpal-0.1.0/uv.lock +199 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(git add:*)",
|
|
5
|
+
"Bash(git commit:*)",
|
|
6
|
+
"Bash(python:*)",
|
|
7
|
+
"Bash(.venv/bin/pip install:*)",
|
|
8
|
+
"Bash(/Users/hanchaoran/Documents/yeyecha/markdownpal/.venv/bin/pip install:*)",
|
|
9
|
+
"Bash(/Users/hanchaoran/Documents/yeyecha/markdownpal/.venv/bin/python:*)",
|
|
10
|
+
"Bash(python3:*)",
|
|
11
|
+
"Bash(.venv/bin/pytest:*)"
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# MarkdownPal Examples
|
|
2
|
+
|
|
3
|
+
## Quick Start
|
|
4
|
+
|
|
5
|
+
```python
|
|
6
|
+
from markdownpal import Document
|
|
7
|
+
from markdownpal.blocks import H1Block, TextBlock
|
|
8
|
+
from markdownpal.inline import bold
|
|
9
|
+
|
|
10
|
+
doc = Document()
|
|
11
|
+
doc.append(H1Block("Hello, MarkdownPal"))
|
|
12
|
+
doc.append(TextBlock(f"Build {bold('Markdown')} files with Python."))
|
|
13
|
+
doc.save("output.md")
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Block Types
|
|
19
|
+
|
|
20
|
+
### Headings
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from markdownpal.blocks import H1Block, H2Block, H3Block, H4Block, H5Block, H6Block
|
|
24
|
+
|
|
25
|
+
doc.append(H1Block("Title")) # # Title
|
|
26
|
+
doc.append(H2Block("Section")) # ## Section
|
|
27
|
+
doc.append(H3Block("Subsection")) # ### Subsection
|
|
28
|
+
doc.append(H4Block("Detail")) # #### Detail
|
|
29
|
+
doc.append(H5Block("Minor")) # ##### Minor
|
|
30
|
+
doc.append(H6Block("Tiny")) # ###### Tiny
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Text & Formatting
|
|
34
|
+
|
|
35
|
+
```python
|
|
36
|
+
from markdownpal.blocks import TextBlock, QuoteBlock, HRBlock, CommentBlock
|
|
37
|
+
from markdownpal.inline import bold, italic, code, strikethrough
|
|
38
|
+
|
|
39
|
+
doc.append(TextBlock("Plain paragraph."))
|
|
40
|
+
doc.append(TextBlock(f"{bold('Bold')}, {italic('italic')}, {code('inline code')}, {strikethrough('struck')}."))
|
|
41
|
+
doc.append(QuoteBlock("A quote that spans\nmultiple lines."))
|
|
42
|
+
doc.append(HRBlock())
|
|
43
|
+
doc.append(CommentBlock("This comment is invisible in rendered output."))
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Code
|
|
47
|
+
|
|
48
|
+
```python
|
|
49
|
+
from markdownpal.blocks import CodeBlock
|
|
50
|
+
|
|
51
|
+
doc.append(CodeBlock("print('hello world')", lang="python"))
|
|
52
|
+
doc.append(CodeBlock("SELECT * FROM users;", lang="sql"))
|
|
53
|
+
doc.append(CodeBlock("plain code block, no highlighting"))
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Lists
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from markdownpal.blocks import ULBlock, OLBlock, TaskListBlock
|
|
60
|
+
|
|
61
|
+
doc.append(ULBlock(["Apples", "Bananas", "Cherries"]))
|
|
62
|
+
|
|
63
|
+
doc.append(OLBlock(["Install", "Configure", "Run"]))
|
|
64
|
+
|
|
65
|
+
doc.append(TaskListBlock([
|
|
66
|
+
("Write tests", True),
|
|
67
|
+
("Write code", True),
|
|
68
|
+
("Deploy", False),
|
|
69
|
+
]))
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Table
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from markdownpal.blocks import TableBlock
|
|
76
|
+
|
|
77
|
+
doc.append(TableBlock(
|
|
78
|
+
headers=["Name", "Role", "Status"],
|
|
79
|
+
rows=[
|
|
80
|
+
["Alice", "Engineer", "✅ Active"],
|
|
81
|
+
["Bob", "Designer", "✅ Active"],
|
|
82
|
+
["Carol", "PM", "🔄 Onboarding"],
|
|
83
|
+
]
|
|
84
|
+
))
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Images & Links
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
from markdownpal.blocks import ImageBlock, LinkBlock
|
|
91
|
+
|
|
92
|
+
doc.append(ImageBlock(src="https://example.com/logo.png", alt="Project Logo"))
|
|
93
|
+
doc.append(ImageBlock(src="diagram.png")) # alt is optional
|
|
94
|
+
doc.append(LinkBlock(text="Documentation", url="https://example.com/docs"))
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Inline Helpers
|
|
100
|
+
|
|
101
|
+
Inline helpers return strings and can be composed or embedded inside any block content:
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
from markdownpal.inline import bold, italic, code, strikethrough
|
|
105
|
+
|
|
106
|
+
bold("important") # **important**
|
|
107
|
+
italic("note") # *note*
|
|
108
|
+
code("os.path.join()") # `os.path.join()`
|
|
109
|
+
strikethrough("deprecated") # ~~deprecated~~
|
|
110
|
+
|
|
111
|
+
# Composable
|
|
112
|
+
bold(italic("emphasis")) # ***emphasis***
|
|
113
|
+
|
|
114
|
+
# Embed in blocks
|
|
115
|
+
TextBlock(f"See {code('render()')} for details.")
|
|
116
|
+
H2Block(f"API {italic('Reference')}")
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## Render to String
|
|
122
|
+
|
|
123
|
+
Use `render()` to get the Markdown string directly without saving to disk:
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
doc = MarkdownDocument()
|
|
127
|
+
doc.append(H1Block("Report"))
|
|
128
|
+
doc.append(TextBlock("Generated automatically."))
|
|
129
|
+
|
|
130
|
+
output = doc.render()
|
|
131
|
+
print(output)
|
|
132
|
+
# # Report
|
|
133
|
+
#
|
|
134
|
+
# Generated automatically.
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Save to File
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
doc.save("report.md") # relative path
|
|
143
|
+
doc.save("/tmp/docs/report.md") # absolute path
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Files are written in UTF-8 and fully support international characters and emoji:
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
doc.append(H1Block("项目文档"))
|
|
150
|
+
doc.append(TextBlock("支持中文、日本語、한국어 및 emoji 🎉"))
|
|
151
|
+
doc.save("国际化.md")
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## Complete Example
|
|
157
|
+
|
|
158
|
+
```python
|
|
159
|
+
from markdownpal import Document
|
|
160
|
+
from markdownpal.blocks import (
|
|
161
|
+
H1Block, H2Block, H3Block,
|
|
162
|
+
TextBlock, CodeBlock, TableBlock,
|
|
163
|
+
ULBlock, TaskListBlock, HRBlock,
|
|
164
|
+
)
|
|
165
|
+
from markdownpal.inline import bold, italic, code
|
|
166
|
+
|
|
167
|
+
doc = Document()
|
|
168
|
+
|
|
169
|
+
doc.append(H1Block("Project Changelog"))
|
|
170
|
+
doc.append(TextBlock(f"All notable changes are documented here. Format based on {bold('Keep a Changelog')}."))
|
|
171
|
+
doc.append(HRBlock())
|
|
172
|
+
|
|
173
|
+
doc.append(H2Block("v1.2.0 — 2026-04-12"))
|
|
174
|
+
doc.append(H3Block("Added"))
|
|
175
|
+
doc.append(ULBlock([
|
|
176
|
+
f"{code('TaskListBlock')} for checkbox lists",
|
|
177
|
+
"UTF-8 file output via save()",
|
|
178
|
+
"Inline helpers: bold, italic, code, strikethrough",
|
|
179
|
+
]))
|
|
180
|
+
|
|
181
|
+
doc.append(H3Block("Fixed"))
|
|
182
|
+
doc.append(ULBlock([
|
|
183
|
+
f"{code('QuoteBlock')} now correctly handles multi-line text",
|
|
184
|
+
]))
|
|
185
|
+
|
|
186
|
+
doc.append(H2Block("Compatibility"))
|
|
187
|
+
doc.append(TableBlock(
|
|
188
|
+
headers=["Python", "Supported"],
|
|
189
|
+
rows=[
|
|
190
|
+
["3.9", "✅"],
|
|
191
|
+
["3.10", "✅"],
|
|
192
|
+
["3.11", "✅"],
|
|
193
|
+
["3.12", "✅"],
|
|
194
|
+
]
|
|
195
|
+
))
|
|
196
|
+
|
|
197
|
+
doc.append(H2Block("Installation"))
|
|
198
|
+
doc.append(CodeBlock("pip install markdownpal", lang="bash"))
|
|
199
|
+
|
|
200
|
+
doc.save("CHANGELOG.md")
|
|
201
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Rogerstacker
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: markdownpal
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A pure-Python library for programmatically generating Markdown files.
|
|
5
|
+
Project-URL: Homepage, https://github.com/rogerstacker/markdownpal
|
|
6
|
+
Project-URL: Repository, https://github.com/rogerstacker/markdownpal
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/rogerstacker/markdownpal/issues
|
|
8
|
+
Author-email: Rogerstacker <rogerstacker3rd@gmail.com>
|
|
9
|
+
License: MIT License
|
|
10
|
+
|
|
11
|
+
Copyright (c) 2026 Rogerstacker
|
|
12
|
+
|
|
13
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
14
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
15
|
+
in the Software without restriction, including without limitation the rights
|
|
16
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
17
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
18
|
+
furnished to do so, subject to the following conditions:
|
|
19
|
+
|
|
20
|
+
The above copyright notice and this permission notice shall be included in all
|
|
21
|
+
copies or substantial portions of the Software.
|
|
22
|
+
|
|
23
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
24
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
25
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
26
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
27
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
28
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
29
|
+
SOFTWARE.
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Keywords: builder,document,generator,markdown
|
|
32
|
+
Classifier: Intended Audience :: Developers
|
|
33
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
34
|
+
Classifier: Operating System :: OS Independent
|
|
35
|
+
Classifier: Programming Language :: Python :: 3
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
40
|
+
Classifier: Topic :: Text Processing :: Markup
|
|
41
|
+
Requires-Python: >=3.9
|
|
42
|
+
Provides-Extra: dev
|
|
43
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
44
|
+
Description-Content-Type: text/markdown
|
|
45
|
+
|
|
46
|
+
# MarkdownPal
|
|
47
|
+
|
|
48
|
+
A pure-Python library for programmatically generating Markdown (`.md`) files via a clean, block-based document builder API.
|
|
49
|
+
|
|
50
|
+
[](https://www.python.org/)
|
|
51
|
+
[](LICENSE)
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Features
|
|
56
|
+
|
|
57
|
+
- **Block-based API** — compose documents from typed, self-contained block objects
|
|
58
|
+
- **Inline formatting helpers** — `bold()`, `italic()`, `code()`, `strikethrough()`
|
|
59
|
+
- **Full block support** — headings, paragraphs, quotes, code, lists, tables, images, links
|
|
60
|
+
- **Save to file** — UTF-8 output with full support for international characters and emoji
|
|
61
|
+
- **Zero dependencies** — no third-party packages required
|
|
62
|
+
- **Python 3.9+**
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Installation
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pip3 install markdownpal
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## Quick Start
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from markdownpal import Document
|
|
78
|
+
from markdownpal.blocks import H1Block, H2Block, TextBlock, CodeBlock, ULBlock
|
|
79
|
+
from markdownpal.inline import bold
|
|
80
|
+
|
|
81
|
+
doc = Document()
|
|
82
|
+
|
|
83
|
+
doc.append(H1Block("My Project"))
|
|
84
|
+
doc.append(TextBlock(f"A {bold('simple')} example of MarkdownPal."))
|
|
85
|
+
doc.append(H2Block("Installation"))
|
|
86
|
+
doc.append(CodeBlock("pip install markdownpal", lang="bash"))
|
|
87
|
+
doc.append(H2Block("Features"))
|
|
88
|
+
doc.append(ULBlock(["Zero dependencies", "Clean API", "Python 3.9+"]))
|
|
89
|
+
|
|
90
|
+
doc.save("output.md")
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Output (`output.md`):
|
|
94
|
+
|
|
95
|
+
```markdown
|
|
96
|
+
# My Project
|
|
97
|
+
|
|
98
|
+
A **simple** example of MarkdownPal.
|
|
99
|
+
|
|
100
|
+
## Installation
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
pip install markdownpal
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Features
|
|
107
|
+
|
|
108
|
+
- Zero dependencies
|
|
109
|
+
- Clean API
|
|
110
|
+
- Python 3.9+
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Block Reference
|
|
116
|
+
|
|
117
|
+
### Headings
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
from markdownpal.blocks import H1Block, H2Block, H3Block, H4Block, H5Block, H6Block
|
|
121
|
+
|
|
122
|
+
doc.append(H1Block("Title")) # # Title
|
|
123
|
+
doc.append(H2Block("Section")) # ## Section
|
|
124
|
+
doc.append(H3Block("Subsection")) # ### Subsection
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Text
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
from markdownpal.blocks import TextBlock, QuoteBlock, HRBlock, CommentBlock
|
|
131
|
+
|
|
132
|
+
doc.append(TextBlock("A plain paragraph."))
|
|
133
|
+
doc.append(QuoteBlock("A blockquote.\nSpanning multiple lines."))
|
|
134
|
+
doc.append(HRBlock()) # ---
|
|
135
|
+
doc.append(CommentBlock("Hidden in rendered output.")) # <!-- ... -->
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Code
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
from markdownpal.blocks import CodeBlock
|
|
142
|
+
|
|
143
|
+
doc.append(CodeBlock("print('hello')", lang="python"))
|
|
144
|
+
doc.append(CodeBlock("SELECT * FROM users;", lang="sql"))
|
|
145
|
+
doc.append(CodeBlock("no language specified"))
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Lists
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
from markdownpal.blocks import ULBlock, OLBlock, TaskListBlock
|
|
152
|
+
|
|
153
|
+
doc.append(ULBlock(["Apples", "Bananas", "Cherries"]))
|
|
154
|
+
|
|
155
|
+
doc.append(OLBlock(["Install", "Configure", "Run"]))
|
|
156
|
+
|
|
157
|
+
doc.append(TaskListBlock([
|
|
158
|
+
("Write tests", True),
|
|
159
|
+
("Write code", True),
|
|
160
|
+
("Deploy", False),
|
|
161
|
+
]))
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Table
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
from markdownpal.blocks import TableBlock
|
|
168
|
+
|
|
169
|
+
doc.append(TableBlock(
|
|
170
|
+
headers=["Name", "Role", "Status"],
|
|
171
|
+
rows=[
|
|
172
|
+
["Alice", "Engineer", "Active"],
|
|
173
|
+
["Bob", "Designer", "Active"],
|
|
174
|
+
]
|
|
175
|
+
))
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### Images & Links
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
from markdownpal.blocks import ImageBlock, LinkBlock
|
|
182
|
+
|
|
183
|
+
doc.append(ImageBlock(src="logo.png", alt="Project Logo"))
|
|
184
|
+
doc.append(LinkBlock(text="Documentation", url="https://example.com/docs"))
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## Inline Helpers
|
|
190
|
+
|
|
191
|
+
Inline helpers return plain strings and can be embedded inside any block content:
|
|
192
|
+
|
|
193
|
+
```python
|
|
194
|
+
from markdownpal.inline import bold, italic, code, strikethrough
|
|
195
|
+
|
|
196
|
+
bold("important") # **important**
|
|
197
|
+
italic("note") # *note*
|
|
198
|
+
code("os.path.join()") # `os.path.join()`
|
|
199
|
+
strikethrough("deprecated") # ~~deprecated~~
|
|
200
|
+
|
|
201
|
+
# Composable
|
|
202
|
+
bold(italic("emphasis")) # ***emphasis***
|
|
203
|
+
|
|
204
|
+
# Embed in blocks
|
|
205
|
+
doc.append(TextBlock(f"Call {code('render()')} to get the output string."))
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Document API
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
doc = Document()
|
|
214
|
+
doc.append(block) # Add a Block instance
|
|
215
|
+
doc.render() # Returns the full Markdown string
|
|
216
|
+
doc.save("out.md") # Writes UTF-8 Markdown file to disk
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
`append()` raises `TypeError` if the argument is not a `Block` instance.
|
|
220
|
+
`render()` joins all blocks with a blank line (`\n\n`) between them.
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Project Structure
|
|
225
|
+
|
|
226
|
+
```
|
|
227
|
+
markdownpal/
|
|
228
|
+
├── __init__.py # Top-level public API
|
|
229
|
+
├── document.py # Document class
|
|
230
|
+
├── inline.py # Inline format helpers
|
|
231
|
+
└── blocks/
|
|
232
|
+
├── base.py # Block abstract base class
|
|
233
|
+
├── heading.py # H1Block ~ H6Block
|
|
234
|
+
├── text.py # TextBlock, QuoteBlock, HRBlock, CommentBlock
|
|
235
|
+
├── code.py # CodeBlock
|
|
236
|
+
├── list_.py # ULBlock, OLBlock, TaskListBlock
|
|
237
|
+
├── table.py # TableBlock
|
|
238
|
+
└── media.py # ImageBlock, LinkBlock
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Development
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
# Clone the repository
|
|
247
|
+
git clone https://github.com/rogerstacker/markdownpal.git
|
|
248
|
+
cd markdownpal
|
|
249
|
+
|
|
250
|
+
# Install dev dependencies
|
|
251
|
+
pip3 install -e ".[dev]"
|
|
252
|
+
|
|
253
|
+
# Run tests
|
|
254
|
+
pytest
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## License
|
|
260
|
+
|
|
261
|
+
[MIT](LICENSE) © 2026 Rogerstacker
|