一个使用 Rust 编写的 Markdown AST 解析器。
Painted Markdown 是一个 AST-first 的 Markdown 解析器:
- 输入 Markdown,输出结构化 AST(包含节点类型、层级与位置信息)。
- 目标兼容 CommonMark / GFM / OFM,供上层渲染系统(Web/Node)消费。
- 内置 HTML 渲染主要用于测试与调试,不是主接口。
项目重点是作为上层渲染管线的“语法前端”,尤其是通过 WebAssembly 在 JS 生态中复用 Rust 解析能力。
如果你在寻找极致吞吐和低内存占用,优先考虑事件流解析器(如 pulldown-cmark / cmark)。
[dependencies]
markdown = { path = ".../markdown" }use markdown::{Parser, ParserOptions};
let parser = Parser::new_with_options(
"# Title\n\ncontent",
ParserOptions::default()
.enabled_gfm()
.enabled_ofm()
.enabled_cjk_autocorrect(),
);
let doc = parser.parse();
let node_count = doc.tree.len();
let html = doc.tree.to_html(); // for debug/testinguse markdown::{ParseError, Parser, ParserOptions};
let parser = Parser::new_with_options(
input,
ParserOptions::default()
.with_max_input_bytes(128 * 1024 * 1024)
.with_max_nodes(5_000_000),
);
match parser.parse_checked() {
Ok(doc) => { /* use doc */ }
Err(ParseError::InputTooLarge { limit, actual }) => { /* handle */ }
Err(ParseError::NodeLimitExceeded { limit, actual }) => { /* handle */ }
}import { parse_with_options } from "@ptdgrp/markdown-wasm";
const doc = parse_with_options("# Hello", {
github_flavored: true,
obsidian_flavored: true,
cjk_autocorrect: true,
});
const tree = doc.tree;
const tags = doc.tags; // unsorted string[]
const frontmatter = doc.frontmatter;
const html = doc.to_html(); // debug/testing
// Two-phase parse
// phase 1: parse frontmatter only
const deferred = parse_with_options(content, {
parse_mode: "frontmatter_only",
});
const phase1Ast = deferred.tree; // Document + FrontMatter
if (deferred.frontmatter?.draft) {
// skip
} else {
// phase 2: continue parsing body/inlines
deferred.continue_parse();
const phase2Ast = deferred.tree; // Document + FrontMatter + ...
}parse_mode supports:
"full"(default): one-shot full parse"frontmatter_only": run phase 1 only, then callcontinue_parse()to enter phase 2
tags is returned as an unsorted array. Do not rely on ordering.
import { parse } from "@ptdgrp/markdown-wasm-node";
const doc = parse("This is $e^{i\\pi}+1=0$");
console.log(doc.total_nodes);
console.log(doc.to_html()); // debug/testingfrontmatterfeature 默认启用。- 文档顶部 frontmatter 会作为
MarkdownNode::FrontMatter(..)节点挂在Document下。 - HTML 渲染会忽略该节点。
Blocks
- Thematic-Breaks
- ATX Headings
- Setext headings
- Indented code blocks
- Fenced code blocks
- HTML blocks
- Link reference definitions
- Paragraphs
- Blank lines
- Tables(GFM)
- Block quotes
- List items
- Task list items(GFM)
- Callouts(OFM)
- Footnotes
Inlines
- Backslash escapes
- Entity and numeric character references
- Code spans
- Emphasis and strong emphasis
- Strikethrough(GFM)
- Links
- Internal links(OFM)
- Block reference(OFM)
- Block defining id(OFM)
- Images
- Embedding Files(OFM)
- Math(OFM)
- Autolinks
- Autolinks(GFM)
- RawHTML
- Comments(OFM)
- DisallowedRawHTML(GFM)
- Hard line breaks
- Soft line breaks
- Emoji
- Tag
- Textual content
Other
- Smart Punctuation
- 中文语境优化 chinese-copywriting-guidelines
- 在 delimiter 针对 CJK 符号的特殊处理
- 颜色文字
#fff{这是白色的文本}、:red[这是红色的文本]、:red{这是红色的背景?} - 通过 cmark 测试
Input(&str)
|
V
-----------------
| Parse Blocks
| extract line
| process line
| add line with block_id to inlines
------------------
|
V
------------------
| Parse Inlines
| process block's line
| process delimiter
| process text(merge, cjk autocorrect)
------------------
|
V
Output(AST Tree)
以下流程用于发布 1.0.x(Rust crate + wasm binding):
- 确保工作区干净,避免把无关改动带入发版。
- 修改版本号:
Cargo.toml的markdown版本wasm-binding/Cargo.toml的markdown-binding版本
- 更新
CHANGELOG.md,新增对应版本与日期条目。 - 同步锁文件并做基础检查:
cargo check
cargo test- 提交发版改动:
git add Cargo.toml wasm-binding/Cargo.toml CHANGELOG.md Cargo.lock
git commit -m "release: v1.0.x"- 打 tag 并推送:
git tag v1.0.x
git push origin master
git push origin v1.0.xpublish-wasm.yml会在v*tag push 后自动触发,发布:@ptdgrp/markdown-wasm@ptdgrp/markdown-wasm-node
MIT