The same parser, four times
Over the last year I kept running into the same shape of problem:
- A docs site generator that wanted Markdown chapters turned into navigation JSON.
- A RAG ingestion script where each Markdown file needed to become a list of text chunks plus its frontmatter metadata.
- An n8n flow that took Markdown emails and extracted only the tasklists.
- A static-site backend that accepted user Markdown and needed to validate structure before persisting.
Each one is small on its own. But every time I reached for a different library — remark here, gray-matter there, marked once, a hand-rolled regex once too many — and every time one of them broke on the same edge cases:
- Nested GFM tasklists where the
checkedstate was silently lost - YAML frontmatter that included quoted booleans (parsed as strings, not booleans)
- Tables whose headers contained spaces (regex parsers treated them as one key)
- Code blocks containing Markdown — re-parsed as Markdown instead of fenced code
So I built one endpoint that does it once, properly.
What it returns
POST /v1/parse takes a Markdown body (text/markdown) or a JSON envelope
(application/json) and returns one stable JSON shape:
{
"success": true,
"data": {
"title": "Project Alpha",
"frontmatter": { "title": "Project Alpha", "status": "shipping" },
"headings": [ { "level": 1, "text": "Project Alpha", "id": "project-alpha" } ],
"sections": [ { "heading": { ... }, "children": [ ... ], "content": [ ... ] } ],
"lists": [ { "ordered": false, "items": ["ship MVP", "write README"] } ],
"tasklists": [ { "items": [ { "text": "ship MVP", "checked": true } ] } ],
"tables": [ { "headers": ["Module","Status"], "rows": [{"Module":"API","Status":"Done"}] } ],
"codeBlocks":[ { "lang":