📝 markdown

Markdown Parser & HTML Renderer - CommonMark Compatible

~400 lines ~35 function CommonMark

📖 Overview

Markdown modülü, CommonMark standardına uyumlu Markdown parser and HTML renderer sağlar. AST manipulation, syntax highlighting and table of contents generation destekler.

🔑 Key Features

🚀 Quick Start

import markdown

// Basit rendering
let html = markdown.render("# Hello\nWorld!")
io.println(html)
// Output: <h1>Hello</h1>\n<p>World!</p>

// Dosyadan okuma
let md_text = fs.read_to_string("README.md")?
let html = markdown.render(md_text)
fs.write("README.html", html)?

💡 Example 1: Blog Generator

import markdown, fs, time, regex

struct BlogPost do
    title: str,
    date: time.Date,
    author: str,
    content_html: str,
    excerpt: str,
    reading_time: int
end

function parse_blog_post(md_file: str) -> Result[BlogPost, Error] do
    // Markdown dosyasını oku
    let content = fs.read_to_string(md_file)?
    
    // Front matter parse et (YAML)
    let (frontmatter, body) = split_frontmatter(content)?
    
    let title = frontmatter.get("title")?
    let date = time.parse(frontmatter.get("date")?, "%Y-%m-%d")?
    let author = frontmatter.get("author")?
    
    // Markdown to HTML
    let doc = markdown.parse(body)
    
    // Table of contents ekle
    let toc = markdown.generate_toc(doc)
    
    // Syntax highlighting
    markdown.highlight_code_blocks(doc, do
        theme: "github",
        line_numbers: true
    end)
    
    let html = markdown.to_html(doc)
    
    // Excerpt (first paragraph)
    let excerpt = markdown.extract_text(doc, max_length: 150)
    
    // Reading time (ortalama 200 kelime/dakika)
    let word_count = markdown.word_count(doc)
    let reading_time = (word_count / 200).max(1)
    
    return Ok(BlogPost do
        title: title,
        date: date,
        author: author,
        content_html: html,
        excerpt: excerpt,
        reading_time: reading_time
    end)
end

function generate_blog_html(post: BlogPost) -> str do
    return "
        <article>
            <header>
                <h1>{}</h1>
                <div class='meta'>
                    <span>By {}</span>
                    <span>{}</span>
                    <span>{} min read</span>
                </div>
            </header>
            <div class='excerpt'>{}</div>
            <div class='content'>
                {}
            </div>
        </article>
    ".formatla(
        post.title,
        post.author,
        post.date.format("%B %d, %Y"),
        post.reading_time,
        post.excerpt,
        post.content_html
    )
end

function main() do
    let posts = []
    
    // Tüm blog postlarını parse et
    each file in fs.read_dir("posts")? for do
        if file.ends_with(".md")  do
            match parse_blog_post("posts/" + file) do
                Ok(post) => posts.ekle(post),
                Error(e) => io.eprintln("Error parsing {}: {}", file, e)
            end
        end
    end
    
    // Tarihe göre sırala
    posts.sort_by(|a, b| b.date.cmp(&a.date))
    
    // HTML create
    each post in posts for do
        let html = generate_blog_html(post)
        let slug = post.title.to_lowercase().replace(" ", "-")
        fs.write("output/{}.html".formatla(slug), html)?
    end
    
    io.println("Generated {} blog posts", posts.uzunluk())
end

💡 Example 2: Documentation Generator

import markdown, fs

function generate_docs(input_dir: str, output_dir: str) -> Result[None, Error] do
    // Template
    let template = fs.read_to_string("template.html")?
    
    // Sidebar navigation
    let nav_items = []
    
    // Process all markdown files
    each file in fs.glob("{}/**/*.md".formatla(input_dir))? for do
        let md_text = fs.read_to_string(file)?
        let doc = markdown.parse(md_text)
        
        // Extract title (first h1)
        let title = markdown.find_first_heading(doc, level: 1)
            .unwrap_or("Untitled")
        
        // Generate TOC
        let toc_html = markdown.generate_toc_html(doc, do
            min_level: 2,
            max_level: 4,
            id_prefix: "toc-"
        end)
        
        // Add IDs to headings
        markdown.add_heading_ids(doc)
        
        // Convert to HTML
        let content_html = markdown.to_html(doc)
        
        // Apply template
        let html = template
            .replace("{{title}}", title)
            .replace("{{toc}}", toc_html)
            .replace("{{content}}", content_html)
        
        // Output path
        let rel_path = file.strip_prefix(input_dir)?
        let out_file = "{}/{}.html".formatla(output_dir, 
            rel_path.strip_suffix(".md")?)
        
        fs.create_dir_all(fs.parent(out_file)?)?
        fs.write(out_file, html)?
        
        // Add to navigation
        nav_items.ekle(do
            title: title,
            path: rel_path.replace(".md", ".html")
        end)
        
        io.println("✓ Generated {}", out_file)
    end
    
    // Generate index with navigation
    generate_index(output_dir, nav_items)?
    
    return Ok(None)
end

📦 AST Manipulation

// Parse to AST
let doc = markdown.parse("# Title\nContent")

// Traverse nodes
let root = doc.root()
each node in root.children() for do
    match node.type() do
        NodeType.Heading(level) => do
            io.println("H{}: {}", level, node.text())
        end,
        NodeType.Paragraph => do
            io.println("Paragraph: {}", node.text())
        end,
        _ => do end
    end
end

// Modify AST
let heading = markdown.Node.new_heading(2)
heading.append_text("New Section")
root.append_child(heading)

// Convert back to HTML
let html = markdown.to_html(doc)

🔗 Related Modules

← All Modules