核心概念

了解 unifast 的多阶段编译管线、内置处理阶段以及 MdAst 和 HAst 转换的工作方式。

unifast 通过一条多阶段管线来编译 Markdown。理解这些阶段有助于你配置编译器并选择合适的插件。

编译管线

Input text
  → Parse (Markdown or MDX)
  → IR0: MdAst (Markdown structure)
  → Normalize + Built-in MdAst passes
  → Lower to IR1: HAst (HTML structure)
  → HAst passes (sanitize, highlight, etc.)
  → Emit (HTML string)

每个阶段都会通过一层中间表示(IR)对文档进行转换。

中间表示

IR名称用途
IR0MdAstMarkdown 结构 —— 标题、段落、列表、代码块
IR1HAstHTML 结构 —— 元素、属性、文本节点
IR2JsAst仅 MDX 使用 —— ESM 导入和 JSX 表达式

解析器首先生成 MdAst,再降级为 HAst 以便输出 HTML。MDX 输入还会额外生成用于 JavaScript 输出的 JsAst 节点。

处理阶段

处理阶段是在 AST 的特定阶段上执行的转换。unifast 为常见任务内置了以下处理阶段:

MdAst 阶段(降级为 HTML 之前):

  • Normalize —— 为下游阶段提供一致的结构

  • Slug —— 根据文本内容生成标题 ID

  • TOC —— 从标题中提取目录

  • Definition Resolution —— 解析链接/图像的引用定义

HAst 阶段(降级为 HTML 之后):

  • Sanitize —— 移除不允许的 HTML 元素和属性

  • Highlight —— 为代码块应用语法高亮

  • Cleanup —— 清理多余的节点和空白字符

处理阶段按照所属阶段自动排序 —— 你无需关心它们的执行顺序。

插件

插件是用于配置内置处理阶段的 TypeScript 包。它们不会在编译期间执行任意 JavaScript 代码 —— 而是通过设置选项来控制 Rust 核心处理文档的方式。

import { compile, gfm, sanitize } from "@unifast/node";

const result = compile(source, {
  plugins: [gfm(), sanitize()],
});

每个插件都会返回一个配置对象,在 Rust 核心运行之前被合并到编译选项中。这样就能保证热路径完全运行在原生代码中。

输出格式

编译器通过 outputKind 选项支持多种输出格式:

格式描述
"html"HTML 字符串(默认)
"hast"HAst JSON —— 用于自定义渲染的 HTML AST
"mdast"MdAst JSON —— 用于分析的 Markdown AST
"mdx-js"JavaScript 模块字符串(仅 MDX)

诊断信息

编译器会通过结果中的 diagnostics 数组报告各类问题。每条诊断都包含严重级别、消息,以及可选的源码位置范围,用于精确定位错误。

const result = compile(source);

for (const d of result.diagnostics) {
  console.warn(`[${d.level}] ${d.message}`);
}