All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
postamble(trailing Typst): apostamblefield in[style], document classes, and front matter emits raw Typst after the body, mirroringpreamble(which emits before). This completes the workflow for Typst templates such as faithful-acmart:preambleimports the template and applies its#show: template.with(...)rule, the Markdown becomes the body, andpostambleemits end matter like#bibliography("refs.bib"). Concatenates with config/class postamble (front matter last); a document class replaces the base postamble as it does forpreamble.
cliMermaid backend:--mermaid cli(ormermaid_backend = "cli"in config) pre-renders each diagram to a PDF with the official mermaid-cli (mmdc, i.e. mermaid.js in headless Chrome) and embeds it via#image(...), instead of the defaultmmdrpackage. This is fully faithful to the Mermaid spec — including HTML formatting like<b>bold labels. The PDF page is sized to the diagram's bounding box (mmdc --pdfFit), so there is no surrounding whitespace. Requiresnpm install -g @mermaid-js/mermaid-cliplus a headless Chrome; rendered PDFs are written next to the output. PDF (not SVG) is used because Typst's SVG renderer can't draw the<foreignObject>Mermaid emits for HTML labels (typst#1421).
- Mermaid labels no longer show literal HTML tags on the default
mmdrbackend: its Rust renderer has nohtmlLabelssupport, so inline formatting tags (<b>,<i>,<strong>,<em>, …) previously appeared verbatim in diagrams. They are now stripped from labels;<br/>line breaks are kept. For faithful rendering of such tags, use the new--mermaid clibackend.
- Currency text no longer mis-parsed as math:
$5 to $10 per monthor$5 to $Xis now treated as literal text rather than inline math.markdown-itusesallow_space=False, allow_digits=Falsefordollarmath; inline math must be compact (no spaces inside delimiters, e.g.$E=mc^2$).mistune's math plugin (whose regex has no equivalent options) is no longer enabled by default — opt in with--plugin mathif needed.
-
Footnotes enabled by default:
[^1]footnote references and[^1]: ...definitions now work out of the box on all three parsers (markdown-it, mistune, marko), rendering as Typst#footnote[...].load_plugin()is now idempotent, so explicitly loading the footnote plugin is a no-op. -
Multiple input files:
md2typst *.mdandmd2pdf *.mdnow accept multiple arguments, converting each file in turn -
[TOC]support: A standalone[TOC]paragraph is converted to#outline(indent: auto, depth: 4)for table of contents generation -
Document classes (
article,report,book): Named style presets defined in[classes.<name>]config sections, inspired by LaTeX document classes- Select via front matter (
class: report), CLI (--class report), or config (default_class = "article") - Class preamble replaces (not concatenates with) the base style preamble; scalar fields (font, paper, etc.) are inherited
- article: compact layout, inline title block, no page breaks between sections, flat section numbering
- report: separate title with rule, page breaks before sections, numbered sections (skip level 1), TOC on own page
- book: full title page, two-sided margins for binding, chapters as "Chapter N" on odd pages, running headers, TOC on odd page
- Select via front matter (
-
Title block system (
doc-make-title()): Automatic title page/block generation from front matter metadata- Supported fields:
title,subtitle,author,authors,date,version,publisher - Default function emitted by generator; class preambles can override with custom formatting
- All title variables guaranteed to exist (defaulting to
none)
- Supported fields:
-
Sample documents in
samples/with local config and Makefilearticle.md: academic paper with math, tablesreport.md: technical report with TOC, ASCII diagrams, budget tablesbook.md: multi-chapter book with consensus protocols, replication patterns
- Auto-import scan now traverses
List.items(math inside list items was not triggering package imports)
-
Style configuration system: New
[style]section in config files for customizing Typst output defaults-
Fields:
font(string or list for fallback),font_size,language,paper,margin,preamble -
Translated to
#set text(...)and#set page(...)directives automatically -
Font fallback lists are emitted as Typst tuples, e.g.
font: ("Libertinus Serif", "New Computer Modern") -
User-level config file:
~/.config/md2typst/config.toml(viaplatformdirs, cross-platform)- Lowest priority after built-in defaults
- Purpose: set your preferred default styling (font, language, page setup) once for all documents
-
Extended cascade ordering (lowest to highest priority):
- Built-in defaults
- User config (
~/.config/md2typst/config.toml) pyproject.toml[tool.md2typst]md2typst.toml(searched up from input)- Explicit
--config file.toml - Front matter in the document
- CLI flags
-
Front matter style overrides: Style fields can be set directly in YAML front matter
- Keys:
font,font_size,language,paper,margin - These override the config
[style]section at the document level - Config
style.preambleand front matterpreambleare concatenated (config first)
- Keys:
-
-
Diagram blocks:
```diagramcode blocks are wrapped in#block(breakable: false)to prevent page breaks inside ASCII-art diagrams -
--debugflag: Added to bothmd2typstandmd2pdfcommands; shows effective config, user config path, and generated Typst source
- Added
platformdirsdependency for cross-platform user config directory discovery - Renamed project config file from
.md2typst.tomltomd2typst.toml
- Missing dependency: Added
mdit-py-pluginsto package dependencies (required for math support via dollarmath plugin)
-
Mermaid diagram support:
```mermaidcode blocks are converted to#mermaid("...")calls using the mmdr Typst package- Supported by all three parsers (markdown-it, mistune, marko)
- New
MermaidBlockAST node - Package import (
#import "@preview/mmdr:0.2.1": mermaid) is auto-generated when Mermaid blocks are present
-
Auto-import of Typst packages: Required package imports are now automatically prepended based on AST content
mitexfor math expressions (MathInline,MathBlock)mmdrfor Mermaid diagrams (MermaidBlock)
-
Math enabled by default: Dollar-sign math syntax (
$...$and$$...$$) is now parsed out of the box- markdown-it: dollarmath plugin loaded automatically
- mistune: math plugin loaded automatically
- marko: not supported (no math extension)
- Updated mitex package from 0.2.0 to 0.2.6, fixing
duplicate key: interror at compile time
- Default output to file:
md2typst input.mdnow writesinput.typby default (previously wrote to stdout). Use-o -to output to stdout. Consistent withmd2pdfbehavior. - Refactored CLI into separate module: Split
__init__.pyintocli.py(CLI entry points) andconverter.py(conversion logic). Public API unchanged. - Version from package metadata: Version is now read via
importlib.metadatainstead of being hardcoded.
-
md2pdfcommand: Convert Markdown directly to PDF via Typst- Runs
md2typstthentypst compilein sequence - Uses a temporary
.typfile (automatically cleaned up) - Output defaults to input filename with
.pdfextension - Supports all
md2typstoptions (--parser,--plugin,--stylesheet,--config)
- Runs
-
Front matter preamble: Include raw Typst code via
preamble:in YAML front matter- Supports
#set,#show, and any Typst declarations - Inserted after stylesheet imports, before document content
- Output ordering: variables → imports → preamble → content
- Supports
- Soft breaks now produce Typst linebreaks (
\), preserving single newlines from the source as visible line breaks in the rendered output
-
YAML front matter support: Extract metadata from Markdown files
- Parses YAML between
---delimiters at document start - Generates Typst variables (
#let doc-title = "...") - Supports strings, numbers, booleans, lists, and null values
- Keys with underscores/spaces converted to hyphens (
my_key→doc-my-key)
- Parses YAML between
-
Stylesheet imports: Import Typst modules for styling
- CLI option:
--stylesheet NAME(can be used multiple times) - Config file:
stylesheets = ["style1", "style2"] - Front matter:
stylesheet: my-styleorstylesheets: [style1, style2] - Generates
#import "name.typ": *statements
- CLI option:
-
Preamble support: Include raw Typst code in front matter
- Use
preamble: |in front matter for multi-line Typst code - Inserted after imports, before document content
- Enables
#show: apply-stylepattern for template functions
- Use
- Fixed parentheses after links causing Typst syntax errors
[link](url)(text)now correctly escapes the opening parenthesis
-
Index entries support: Mark terms for inclusion in a document index (markdown-it only)
- New AST node:
IndexEntry(term, subterm, see) - Pandoc-style syntax:
[Python]{.index}or[text]{.index key="Term!Subterm"} - Generator produces Typst
#index("term")or#index("term", "subterm") - Requires
mdit_py_plugins.attrsplugin with markdown-it parser
- New AST node:
-
Math support: LaTeX math syntax with pass-through to Typst's mitex package
- New AST nodes:
MathInlineandMathBlock - Inline math (
$...$) outputs#mi("...") - Display math (
$$...$$) outputs#mitex(...) - Parser support:
- markdown-it-py:
mdit_py_plugins.dollarmath - mistune:
mathplugin - marko: Not supported (no math extension)
- markdown-it-py:
- Requires
#import "@preview/mitex:0.2.0": *in Typst document
- New AST nodes:
- Fixed table generation producing invalid Typst markup.
-
Footnotes support: Full support for Markdown footnotes across all three parsers
- New AST nodes:
FootnoteRef(inline reference) andFootnoteDef(block definition) - Generator produces Typst
#footnote[...]output - Supports named footnotes (
[^note]) and numbered footnotes ([^1]) - Supports multi-paragraph footnotes
- Parser plugins:
- markdown-it-py:
mdit_py_plugins.footnote - mistune:
footnotes(built-in) - marko:
footnote(built-in)
- markdown-it-py:
- New AST nodes:
-
Endnotes support: Alternative to footnotes that collects notes at end of document
- Configure via
output_options.note_style = "endnote"in config file - Or via API:
generate_typst(doc, note_style="endnote") - Produces superscript references (
#super[1]) and a "Notes" section with numbered list - Repeated references to the same note use the same number
- Configure via
-
Added
mdit-py-pluginsas a dev dependency for footnote support -
New integration tests:
tests/b_integration/test_footnotes.py- footnote parsing and generation
- AST dataclasses are now frozen (
@dataclass(frozen=True)) with tuple fields for immutability - Updated
_visit_children_inlineto accepttuple[Node, ...]instead oflist[Node] convert()function now acceptsoutput_optionsparameter for generator configurationconvert_with_config()now passesoutput_optionsfrom config to the generator
- Fixed various typing issues with tuple vs list arguments
- Fixed empty children initialization to use tuples (
()) instead of lists ([])
- Initial release
- Core Markdown to Typst conversion
- Support for three Markdown parsers:
- markdown-it-py (default, CommonMark compliant)
- mistune (fast, pure Python)
- marko (CommonMark compliant)
- Parser-agnostic AST representation
- Typst code generator with visitor pattern
- GFM extensions support:
- Tables with column alignment
- Strikethrough (
~~text~~)
- Configuration system:
- CLI arguments
- TOML config files (
md2typst.toml) - pyproject.toml
[tool.md2typst]section
- Comprehensive test suite:
- Unit tests
- Integration tests
- End-to-end tests
- Property-based testing with Hypothesis
- TCK (Technology Compatibility Kit) for spec compliance
- Benchmarks
- Headings (levels 1-6)
- Paragraphs
- Emphasis (italic) and strong (bold)
- Inline code and code blocks with syntax highlighting
- Links and images
- Block quotes
- Ordered and unordered lists
- Thematic breaks (horizontal rules)
- Hard and soft line breaks
- HTML blocks and inline HTML (preserved as comments)