Incremental Markdown parser and compiler
Dependencies
npm install @mizchi/markdownimport { parse, toHtml, toMarkdown } from "@mizchi/markdown";
// Parse to AST
const ast = parse("# Hello\n\n**Bold** text");
console.log(ast.children[0].type); // "heading"
// Convert to HTML
const html = toHtml("# Hello\n\n**Bold** text");
// => "<h1>Hello</h1>\n<p><strong>Bold</strong> text</p>\n"
// Normalize markdown
const normalized = toMarkdown("# Hello\n\n\n\nWorld");
// => "# Hello\n\nWorld\n"import { createDocument, insertEdit } from "@mizchi/markdown";
// Create document handle
const doc = createDocument("# Hello");
// Access AST, HTML, or Markdown
console.log(doc.ast); // Parsed AST
console.log(doc.toHtml()); // "<h1>Hello</h1>\n"
console.log(doc.toMarkdown()); // "# Hello\n"
// Incremental update (faster than full re-parse)
const edit = insertEdit(7, 6); // Insert 6 chars at position 7
const newDoc = doc.update("# Hello World", edit);
// Free resources when done
doc.dispose();
newDoc.dispose();import { parse, Document, Block, Inline } from "@mizchi/markdown";
const ast: Document = parse("# Hello");
const heading = ast.children[0] as HeadingBlock;
console.log(heading.level); // 1moon add mizchi/markdown// Parse markdown
let result = @markdown.parse("# Hello\n\nWorld")
let doc = result.document
// Serialize back (lossless)
let output = @markdown.serialize(doc)
// Render to HTML
let html = @markdown.render_html(doc)
// Or use convenience function
let html = @markdown.md_to_html("# Hello\n\nWorld")// Initial parse
let result = @markdown.parse(source)
let doc = result.document
// Create edit info
let edit = @markdown.EditInfo::replace(
change_start, // Start position
old_length, // Length of replaced text
new_length // Length of new text
)
// Incremental update (reuses unchanged blocks)
let inc_result = @markdown.parse_incremental(doc, old_source, new_source, edit)
let new_doc = inc_result.documentpnpm install
moon build --target js
pnpm exec vite| Document | Full Parse | Incremental | Speedup |
|---|---|---|---|
| 10 paragraphs | 68.89µs | 7.36µs | 9.4x |
| 50 paragraphs | 327.99µs | 8.67µs | 37.8x |
| 100 paragraphs | 651.14µs | 15.25µs | 42.7x |
pub(all) type AgentId Intpub(all) enum Block {
ThematicBreak(Char, Int, Span, Trivia, Trivia)
Heading(Int, HeadingStyle, Array[Inline], Int, Span, Trivia, Trivia)
Paragraph(Array[Inline], Span, Trivia, Trivia)
FencedCode(FenceMarker, Int, String, String, Int, Span, Trivia, Trivia)
IndentedCode(String, Span, Trivia, Trivia)
Blockquote(Array[Block], Span, Trivia, Trivia)
BulletList(BulletMarker, Bool, Array[ListItem], Span, Trivia, Trivia)
OrderedList(Int, OrderedDelimiter, Bool, Array[ListItem], Span, Trivia, Trivia)
HtmlBlock(String, Span, Trivia, Trivia)
Table(Array[TableCell], Array[TableAlign], Array[Array[TableCell]], Span, Trivia, Trivia)
BlankLines(Int, Span)
FootnoteDefinition(String, Array[Block], Span, Trivia, Trivia)
}pub(all) enum BulletMarker {
Dash
Asterisk
Plus
}impl Eq for BulletMarkerimpl Show for BulletMarkerpub struct CodeBlockInfo {
lang : String
filename : String
meta : String
}pub(all) struct EditInfo {
offset : Int
old_len : Int
new_len : Int
}pub(all) enum EmphasisMarker {
Asterisk
Underscore
}impl Eq for EmphasisMarkerimpl Show for EmphasisMarkerpub(all) enum FenceMarker {
Backtick
Tilde
}impl Eq for FenceMarkerimpl Show for FenceMarkerpub(all) enum HardBreakStyle {
TwoSpaces
Backslash
}impl Eq for HardBreakStyleimpl Show for HardBreakStylepub(all) enum HeadingStyle {
Atx
Setext
}impl Eq for HeadingStyleimpl Show for HeadingStylepub(all) struct IncrementalResult {
document : Document
reused_before : Int
reparsed : Int
reused_after : Int
}pub(all) enum Inline {
Text(String, Span)
SoftBreak(Span)
HardBreak(HardBreakStyle, Span)
Emphasis(EmphasisMarker, Array[Inline], Span)
Strong(EmphasisMarker, Array[Inline], Span)
Strikethrough(Array[Inline], Span)
Code(String, Int, Span)
Link(Array[Inline], String, String, Span)
RefLink(Array[Inline], String, Span)
Autolink(String, Bool, Span)
Image(String, String, String, Span)
RefImage(String, String, Span)
HtmlInline(String, Span)
FootnoteReference(String, Span)
}pub(all) enum OrderedDelimiter {
Dot
Paren
}impl Eq for OrderedDelimiterimpl Show for OrderedDelimiterfn RenderOptions::with_highlighter(highlighter : (CodeBlockInfo, String) -> String) -> RenderOptionsfn RenderOptions::with_simple_highlighter(highlighter : (String, String) -> String) -> RenderOptionspub(all) struct Span {
from : Int
to : Int
}pub(all) enum TableAlign {
Left
Center
Right
None
}impl Eq for TableAlignimpl Show for TableAlignpub(all) struct Trivia {
content : String
}fn md_parse_and_render(source : String, strict? : Bool) -> Stringfn md_parse_incremental(handle : Int, new_source : String, change_start : Int, old_end : Int, new_end : Int) -> Intfn md_render_to_html(handle : Int) -> Stringfn md_render_to_string(handle : Int) -> Stringfn md_to_html_strict(source : String) -> Stringfn parse_incremental(old_doc : Document, old_source : String, new_source : String, edit : EditInfo) -> IncrementalResultIncremental Markdown parser and compiler
Dependencies