Markdown → typed AST → JSON / Markdown / HTML, with a pluggable widget system.
Project description
markast
Markdown → typed AST → JSON / Markdown / HTML
Parse Markdown into a structured, typed tree your front-end can render — natively, server-side, or as JSON.
from markast import parse
doc = parse("# Hello\n\nA paragraph with **bold** and a [link](https://example.com).")
doc.to_json() # str — ship to any client renderer
doc.to_markdown() # str — roundtrip
doc.to_html() # str — server-side render
Why a tree, not HTML?
HTML is a one-way street. Once your content is rendered, the structure is gone — clients can't restyle headings per platform, can't swap a :::video for a native player, can't extract a TOC without re-parsing.
markast keeps the meaning intact. Parse once, render anywhere:
- Native mobile renders headings with platform typography.
- The web renders
:::videoas a custom player; the terminal renders it as a link. - Search indexes the same structured nodes that drive the UI.
- One source of content powers a docs site, a CMS preview, and a CLI.
What you get
| Layer | What it gives you |
|---|---|
| 🌳 AST | Typed nodes (TypedDict), walker/visitor, JSON-Schema export, factory helpers |
| 🧱 Widgets | :::widget containers with typed params, named slots, validation — and a per-parser registry, no global state |
| 🛡️ Rules | Validation diagnostics that never crash — bad content is repaired and a warning is emitted |
| ⚙️ Transforms | AST → AST passes: normalize, slugify, TOC, autolink |
| 🔀 Renderers | Markdown (full roundtrip) and HTML (server-side) — both subclassable |
| 🧰 Parser | CommonMark + GFM (tables, strikethrough, tasklists, autolinks) + footnotes + custom containers |
| ⌨️ CLI | markast parse file.md --format json |
Install
pip install markast
30-second tour
from markast import Parser
from markast.widgets import BaseWidget, WidgetParam
class CalloutWidget(BaseWidget):
name = "callout"
params = {
"level": WidgetParam(str, default="info", choices=["info", "warn", "error"]),
"title": WidgetParam(str, default=None),
}
parser = Parser(widgets=[CalloutWidget], transforms=["normalize", "slugify"])
doc = parser.parse("""
# Welcome
:::callout level=warn title="Heads up"
This is **important** content.
:::
""")
print(doc.to_json(indent=2))
print(doc.to_html())
parser.parse(...) always returns a valid Document. Invalid input is repaired and reported on doc.warnings — the parser never raises on user content.
Documentation
Full docs live at cursland.github.io/markast (English / Español, light & dark).
| 🚀 Getting started | Install, parse, render |
| 🌳 AST reference | Every node type and field |
| 🧱 Widgets | Built-ins and authoring your own |
| ⚙️ Transforms | Built-in passes and custom transforms |
| 🔀 Renderers | Markdown, HTML, and subclassing |
| 🧭 Walker & utilities | Traverse and mutate the AST safely |
| 🌐 Client integration | Patterns for any front-end |
| 🧩 Extending | Custom rules, plugins, tokenizers |
Examples
Runnable scripts in examples/:
basic_parse.py— simplest usagecustom_widget.py— register a widgettransform_pipeline.py— chain transformsrender_html.py— server-side HTMLapi_backend.py— FastAPI handler returning AST JSON
Status
1.0.0 — first stable release. Backwards-compatible changes follow semver.
License
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file markast-1.0.0.tar.gz.
File metadata
- Download URL: markast-1.0.0.tar.gz
- Upload date:
- Size: 63.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
af8c135ee3ae8d39b165751e3b1d3fd5a030251055d271070f4a84126dfe7453
|
|
| MD5 |
fca0883e52afdfdc14ba24f14ce14008
|
|
| BLAKE2b-256 |
b0443f6823333da338dcb7e32c5f7bd70df82c708637e07bcbcafa7890e501a9
|
File details
Details for the file markast-1.0.0-py3-none-any.whl.
File metadata
- Download URL: markast-1.0.0-py3-none-any.whl
- Upload date:
- Size: 71.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
79635f01b6b67a9c123d163705c7c0c1816445ad58854123c29a0a23b6d4f60d
|
|
| MD5 |
2bbfa78e1fc26f124d98a257f868950c
|
|
| BLAKE2b-256 |
07492c0c0ac7f9ec59ba751add40282dbef19c7b88bae76ba7fe1948ab088cec
|