Event-driven Markdown parser with CommonMark, GFM, HTML, and AST support.
///|
test {
let html = @markdown.Html(@commonmark.html_renderers())
@markdown.Processor(@commonmark.rule()).parse(
"# Hello *MoonBit*",
html.sink(),
)
assert_eq(html.to_string(), "<h1>Hello <em>MoonBit</em></h1>\n")
}///|
test {
let ast = @markdown.Ast()
@markdown.Processor(@commonmark.rule()).parse("hello", ast.sink())
let root = ast.result()
assert_eq(
root.to_json().stringify(),
(
#|{"type":"root","children":[{"type":"paragraph","children":[{"type":"text","value":"hello"}]}]}
),
)
}///|
test {
let html = @markdown.Html(@commonmark.html_renderers())
@markdown.Processor(@commonmark.rule()).parse("# Hello", html.sink())
assert_eq(html.to_string(), "<h1>Hello</h1>\n")
}///|
test {
let events = @markdown.Events()
@markdown.Processor(@commonmark.rule()).parse("hello", events.sink())
match events.collect().get(1) {
Some(Text(text)) => assert_eq(text, "hello")
_ => abort("expected text")
}
}///|
test {
let rule = @gfm.rule()
let html = @markdown.Html(@gfm.html_renderers())
@markdown.Processor(rule).parse("~~done~~", html.sink())
assert_eq(html.to_string(), "<p><del>done</del></p>\n")
}///|
test {
let math = @markdown.Rule::inline(
@markdown.RuleName::raw("x:inline:math"),
priority=100,
triggers="$",
fn(ctx, sink) {
let scanner = ctx.scanner()
if !scanner.has_prefix("$") {
NoMatch
} else {
let mut end = 1
while scanner.char_at_offset(end) != Some(36) &&
ctx.offset() + end < ctx.source().length() {
end = end + 1
}
if ctx.offset() + end >= ctx.source().length() {
NoMatch
} else {
match scanner.slice(1, end) {
Some(text) => {
@markdown.EventFragment::element(
Element(@markdown.Tag::raw("x:math")),
children=[@markdown.EventFragment::text(text)],
).emit_to(sink)
Match(ConsumedChars(end + 1))
}
None => NoMatch
}
}
}
},
)
let html = @markdown.Html(@commonmark.html_renderers())
let rule = @commonmark.rule().extend(math)
@markdown.Processor(rule).parse("Euler: $x + y$", html.sink())
assert_eq(html.to_string(), "<p>Euler: <x:math>x + y</x:math></p>\n")
}///|
test {
let no_raw_html = @markdown.Rule("no-raw-html")
.disable(@markdown.RuleName::commonmark("block:html"))
.disable(@markdown.RuleName::commonmark("inline:raw_html"))
let html = @markdown.Html(@commonmark.html_renderers())
let rule = @commonmark.rule().extend(no_raw_html)
@markdown.Processor(rule).parse("<span>raw</span>", html.sink())
assert_eq(html.to_string(), "<p><span>raw</span></p>\n")
}///|
test {
let ast = @markdown.Ast()
let sink = ast.sink().text_merge()
sink.emit(Enter(Element(@markdown.Tag::raw("x:note"))))
sink.emit(Text("a"))
sink.emit(Text("b"))
sink.emit(Exit(@markdown.Tag::raw("x:note")))
sink.finish()
let root = ast.result()
assert_eq(
root.to_json().stringify(),
(
#|{"type":"root","children":[{"type":"mdastExtension","name":"x:note","attributes":{},"children":[{"type":"text","value":"ab"}]}]}
),
)
}nix develop
justjust check # all MoonBit modules
just fmt # all MoonBit modules
just test # library tests
just verify
just conformance
just benchpub(all) enum AstNode {
AstRoot(Array[AstNode])
AstParagraph(Array[AstNode])
AstHeading(Int, Array[AstNode])
AstThematicBreak
AstBlockquote(Array[AstNode])
AstList(Bool, Int?, Bool, Array[AstNode])
AstListItem(Bool, Bool?, Array[AstNode])
AstCode(String, String?, String?)
AstHtml(String)
AstText(String)
AstEmphasis(Array[AstNode])
AstStrong(Array[AstNode])
AstInlineCode(String)
AstBreak
AstLink(String, String?, Array[AstNode])
AstImage(String, String?, String)
AstDelete(Array[AstNode])
AstTable(Array[String?], Array[AstNode])
AstTableRow(Array[AstNode])
AstTableCell(String?, Array[AstNode])
AstTableSection(Array[AstNode])
AstExtension(String, Array[Attr], Array[AstNode])
}pub struct BlockContext {
// private fields
}pub struct ConsumedChars {
// private fields
}
fn ConsumedChars::ConsumedChars(value : Int) -> ConsumedCharspub struct ConsumedLines {
// private fields
}
fn ConsumedLines::ConsumedLines(value : Int) -> ConsumedLinespub struct EventFragment {
// private fields
}pub struct Html {
// private fields
}
fn Html::Html(renderers : HtmlRenderers, size_hint? : Int) -> Htmlfn HtmlRenderers::register(self : HtmlRenderers, tag : Tag, f : (HtmlWriter, Element) -> String) -> HtmlRenderersfn HtmlRenderers::replace(self : HtmlRenderers, tag : Tag, f : (HtmlWriter, Element) -> String) -> HtmlRendererspub struct HtmlWriter {
// private fields
}fn HtmlWriter::write_attrs_except1(self : HtmlWriter, attrs : Array[Attr], excluded : String) -> Unitfn HtmlWriter::write_attrs_except2(self : HtmlWriter, attrs : Array[Attr], first : String, second : String) -> Unitfn HtmlWriter::write_attrs_except3(self : HtmlWriter, attrs : Array[Attr], first : String, second : String, third : String) -> Unitpub struct InlineContext {
// private fields
}pub struct InlineScanner {
// private fields
}pub struct ParserServices {
// private fields
}fn ParserServices::collect_block_lines(self : ParserServices, lines : Array[String], line_starts : Array[Int]) -> Unitfn ParserServices::parse_block_lines(self : ParserServices, lines : Array[String], line_starts : Array[Int], sink : Sink) -> Unitfn ParserServices::set_state_string(self : ParserServices, key : StateKey, item : String, value : String) -> Unitfn Rule::block(name : RuleName, priority? : Int, before? : Array[RuleName], after? : Array[RuleName], triggers? : String, f : (BlockContext) -> BlockRuleResult) -> Rulefn Rule::block_continue(name : RuleName, priority? : Int, before? : Array[RuleName], after? : Array[RuleName], triggers? : String, f : (BlockContext) -> BlockRuleResult) -> Rulefn Rule::delimiter(name : RuleName, priority? : Int, before? : Array[RuleName], after? : Array[RuleName], triggers? : String, f : (InlineContext, Sink) -> InlineRuleResult) -> Rulefn Rule::inline(name : RuleName, priority? : Int, before? : Array[RuleName], after? : Array[RuleName], triggers? : String, f : (InlineContext, Sink) -> InlineRuleResult) -> Rulepub struct SourceRange {
// private fields
}pub struct StateKey {
// private fields
}
fn StateKey::StateKey(scope : String, name : String) -> StateKeyInstall
Download zipEvent-driven Markdown parser with CommonMark, GFM, HTML, and AST support.