markdown

Parse Markdown into a block list, render it to HTML, and pull out the headings, code blocks and tables a docs pipeline or RAG ingest actually wants. Pure - no capabilities.

ecko get github.com/ecko-lang/markdown
import markdown

Pure computation: it declares no capabilities, so it cannot touch the network, the filesystem or the environment.

Version 0.36.0 - source - MIT.


parse(src)

Parse Markdown into a list of block maps.

Every block has a kind, and the fields that go with it:

  • heading -> level (1-6), text
  • paragraph -> text
  • code -> lang (may be ""), code
  • list -> ordered (bool), items (list of strings)
  • table -> headers (list), rows (list of lists)
  • quote -> text
  • rule -> no extra fields

Blocks come back in document order, so parse then a for loop is the whole walking story - there is no separate visitor to learn.

to_html(src)

Render Markdown to HTML.

Text is HTML-escaped before any tag is added, so a document cannot inject markup - <script> in the source comes out as &lt;script&gt;, including inside code blocks and link text.

headings(src)

Every heading, as { level, text }, in document order.

The shape a table of contents or a doc-structure check wants.

code_blocks(src)

Every fenced code block, as { lang, code }.

lang is whatever followed the fence, or "" when the fence was bare - so filtering by language is filter(fn(c) c.lang == "ecko").

tables(src)

Every table, as { headers, rows }.

A table needs the |---| separator row under its header to be recognised, which is what keeps a paragraph that happens to contain a pipe from being read as one.

text(src)

The document as plain text, with the markup removed.

For embedding and search: headings, paragraphs, list items, quotes and table cells come through as text, and code blocks are dropped - a vector of a code sample rarely answers the question someone asked in prose. Use code_blocks when you want those.

sections(src)

Split a document into { heading, level, body } sections, one per heading.

This is the chunking a RAG ingest wants: each section carries the heading it sits under, so a retrieved chunk knows what it is about. Text before the first heading comes back with an empty heading and level 0 rather than being dropped.