Transforms

AST-to-AST mutations applied after parsing and before serialisation. They bake in cross-cutting behaviour without polluting the parser or renderer.

Built-in transforms

IdentifierClassWhat it does
normalizeNormalizeTextMerge adjacent text nodes, drop empty ones.
slugifySlugifyHeadingsAdd a stable id to every heading.
tocBuildTOCBuild a nested table-of-contents in doc.meta["toc"]. Requires slugify.
linkifyLinkifyConvert bare URLs in text to link nodes.
smarttypographySmartTypographyReplace dashes/quotes/ellipses with typographic equivalents.

Apply them by name when constructing a parser:

from markast import Parser

parser = Parser(transforms=["normalize", "slugify", "toc"])
doc = parser.parse("# Top\n\n## Sub\n\n# Top2")

print(doc.meta["toc"])
# [
#   {"level": 1, "text": "Top",  "id": "top",  "children": [
#       {"level": 2, "text": "Sub", "id": "sub", "children": []}
#   ]},
#   {"level": 1, "text": "Top2", "id": "top2", "children": []}
# ]

Order matters

Transforms run in the order you list them. toc reads ids set by slugify, so slugify must come first.

Writing a custom transform

from markast.transforms import Transform
from markast.ast import replace
from markast import NodeType


class StripDividers(Transform):
    """Remove every horizontal rule from the document."""

    name = "strip-dividers"

    def apply(self, doc, config):
        return replace(doc, lambda n: None if n.get("type") == NodeType.DIVIDER else n)

Register it:

parser = Parser(transforms=[StripDividers])
!
Three things to remember: (1) receive and return a document, (2) use markast.ast.replace for rewrites — it handles every container shape correctly, (3) use doc["meta"] to expose computed data rather than rewriting the tree to fit it.

Transforms vs. rules

TransformRule (markast.rules)
WhenAfter parsing, before renderingDuring parsing
WhatMutates / annotates the ASTObserves and reports diagnostics
Side effectChanges the outputAdds entries to doc.warnings
Use forSlugs, TOCs, autolinks, normalisationCross-cutting validation, lints

Pick a rule when you want to flag something. Pick a transform when you want to change something.