AST Transformation & Pipeline Ordering
Updated 5 min ago
How raw HTML strings are transformed into extended MDAST nodes and why early plugin execution is critical.
Markdown parsers like remark-parse do not parse embedded HTML tags into rich syntax trees; instead, they emit raw string literals as { type: "html", value: "..." } nodes. @m2d/html bridges this gap by preprocessing the Markdown Abstract Syntax Tree (MDAST) and transforming raw HTML into semantic MDAST nodes before DOCX generation begins.
The Tag-Matching Stack Architecture
In Markdown, inline HTML tags frequently wrap Markdown elements across disparate sibling nodes:
<span style="color: red">**Bold alert text** and regular text</span>In the raw MDAST, this produces three separate nodes:
htmlnode (<span style="color: red">)strongnode (**Bold alert text**)textnode (and regular text)htmlnode (</span>)
@m2d/html implements a stack-based preprocessor during the preprocess plugin lifecycle hook:
- It maintains an
htmlNodeStackto track open tags. - Sibling markdown nodes appearing between an opening and closing tag are collected as children of an extended MDAST container.
- Upon encountering the closing tag, the plugin inspects the DOM element, extracts CSS attributes (colors, alignments, weights), and applies them directly to the node's
datapayload.
Pipeline Execution Order: Register Early
Because @m2d/html executes during the preprocess hook, it operates before block-level and inline-level processors:
import { toDocx } from "@m2d/core";
import { htmlPlugin } from "@m2d/html";
import { imagePlugin } from "@m2d/image";
import { tablePlugin } from "@m2d/table";
import { listPlugin } from "@m2d/list";
const docxBlob = await toDocx(mdast, {}, {
plugins: [
htmlPlugin(), // 1. MUST BE FIRST: Converts raw HTML to semantic MDAST nodes
imagePlugin(), // 2. Resolves and rasterizes <img> nodes created by htmlPlugin
tablePlugin(), // 3. Formats <table> nodes created by htmlPlugin
listPlugin(), // 4. Formats <ul>/<ol> nodes created by htmlPlugin
],
});⚠️ Important: If htmlPlugin() is registered after imagePlugin() or tablePlugin(), HTML image tags (<img src="...">) or HTML tables (<table>...</table>) will remain raw, unprocessed string literals and will be omitted from the output Word document.