/**
 * @public
 */
export var TextFormatters;
(function (TextFormatters) {
    /**
     * This function does not apply any formatting to the text.
     *
     * @public
     */
    TextFormatters.DEFAULT = (value) => value;
    /**
     * Formats a WhatsApp-style rich text into HTML.
     *
     * This formatter intentionally targets the **practical WhatsApp message syntax** (as commonly typed),
     * not full Markdown. It focuses on predictable rendering for chat-/note-like UIs.
     *
     * ## Supported syntax
     *
     * ### Inline formatting
     * - Bold:
     *   - `*text*` → `<strong>text</strong>`
     * - Italic:
     *   - `_text_` → `<em>text</em>`
     * - Underline:
     *   - `++text++` → `<u>text</u>`
     * - Double-underline:
     *   - `+++text+++` → `<u style="text-decoration-style: double;">text</u>`
     * - Strikethrough:
     *   - `~text~` → `<del>text</del>`
     * - Colored text:
     *   - `{red}text{/red}` → `<span style="color:red;">text</span>`
     *   - Supports any valid CSS color value (named colors, hex, rgb, css-vars etc.)
     *
     * ### Code
     * - Inline code:
     *   - `` `code` `` → `<code>code</code>`
     * - Code block (fenced):
     *   - <code>```multi line```</code> → `<pre><code>...</code></pre>`
     *   - Code content is HTML-escaped and protected first, so formatting markers inside code are not interpreted.
     *
     * ### Block-level syntax (line-based)
     * - Horizontal rule:
     *   - `---` or `***` or `___` (alone on a line) → `<hr>`
     * - Bulleted list items:
     *   - `- item` or `* item` at line start
     *   - Consecutive bullet lines are grouped into a single `<ul>`.
     * - Numbered list items:
     *   - `1. item`, `2. item`, ... at line start
     *   - Consecutive numbered lines are grouped into a single `<ol>`.
     * - Block quotes:
     *   - `> quoted text` at line start
     *   - Consecutive quote lines are grouped into a single `<blockquote>`.
     *
     * ### Autolinks
     * - Explicit links (Markdown-style):
     *   - `[text](url)` → `<a href="url">text</a>`
     * - URLs:
     *   - `http(s)://...` or `ftp://...` → `<a href="...">...</a>`
     * - Email addresses:
     *   - `name@example.com` → `<a href="mailto:name@example.com">...</a>`
     * - Phone numbers (heuristic):
     *   - `+49 ...` / `0123 ...` (digits with spaces/hyphens/parentheses) → `<a href="tel:...">...</a>`
     *
     * ### New lines
     * - Normal lines are separated with `<br>`.
     * - Lists and blockquotes are rendered structurally (no stray `<br>` between `<li>` items).
     *
     * ## Parsing rules and limitations
     * - Code spans/blocks are tokenized **before** any other parsing to prevent accidental formatting inside code.
     * - URLs/emails/phones are tokenized before emphasis so markers can’t break generated `<a href="...">`.
     * - This is not a full WhatsApp renderer (edge cases and platform-specific quirks are intentionally out of scope).
     *
     * ## Security note
     * This formatter outputs HTML. If `input` is user-generated and the result is rendered via `innerHTML`,
     * ensure the output is sanitized/validated according to your app’s security requirements.
     *
     * @public
     */
    TextFormatters.RICHTEXT = (input) => {
        if (!input)
            return '';
        // Normalize line endings
        let value = input.replace(/\r\n/g, '\n');
        // --- Protect code blocks and inline code first (so they don't get formatted inside) ---
        const TOKEN_START = '\uE000';
        const TOKEN_END = '\uE001';
        const tokens = [];
        const putToken = (html) => {
            const id = tokens.length;
            tokens.push(html);
            return `${TOKEN_START}${id}${TOKEN_END}`;
        };
        const escapeHtml = (s) => s
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#39;');
        // Code block: ``` ... ``` (multiline)
        value = value.replace(/```([\s\S]*?)```/g, (_m, code) => {
            // Keep exactly as-is, but HTML-escape it
            const safe = escapeHtml(code);
            return putToken(`<pre><code class="mosaik-code">${safe}</code></pre>`);
        });
        // Inline code: `...` (single line, but allow anything except backtick)
        value = value.replace(/`([^`\n]+?)`/g, (_m, code) => {
            const safe = escapeHtml(code);
            return putToken(`<code class="mosaik-inlinecode">${safe}</code>`);
        });
        // --- Inline formatting (bold/italic/strike) + links/emails/phones ---
        const formatInline = (text) => {
            let t = text;
            // Italic: _text_ (avoid matching inside words like foo_bar)
            t = t.replace(/(?<!\w)_(\S(?:.*?\S)?)_(?!\w)/g, '<em class="mosaik-italic">$1</em>');
            // Bold: *text*
            t = t.replace(/(?<!\w)\*(\S(?:.*?\S)?)\*(?!\w)/g, '<strong class="mosaik-bold">$1</strong>');
            // Double-underline: +++text+++ (must come before single underline)
            t = t.replace(/(?<!\w)\+\+\+(\S(?:.*?\S)?)\+\+\+(?!\w)/g, '<u class="mosaik-doubleunderline" style="text-decoration-style: double;">$1</u>');
            // Underline: ++text++
            t = t.replace(/(?<!\w)\+\+(\S(?:.*?\S)?)\+\+(?!\w)/g, '<u class="mosaik-underline">$1</u>');
            // Strikethrough: ~text~
            t = t.replace(/(?<!\w)~(\S(?:.*?\S)?)~(?!\w)/g, '<del class="mosaik-strikethrough">$1</del>');
            // Colored text: {color}text{/color}
            // Supports named colors, hex (#fff, #ffffff), rgb(), hsl(), etc.
            // Include trailing space inside span to prevent whitespace collapse in flex/webkit-box layouts
            t = t.replace(/\{([a-zA-Z]+|#[0-9a-fA-F]{3,6}|rgb\([^)]+\)|hsl\([^)]+\))\}([\s\S]*?)\{\/\1\}( ?)/g, '<span class="mosaik-colored" style="color:$1;">$2$3</span>');
            // Markdown-style links: [text](url) - must come BEFORE autolinks to prevent double-processing
            t = t.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a class="mosaik-link" href="$2">$1</a>');
            // URLs (http/https/ftp) - only match URLs not already inside an href attribute
            t = t.replace(/(?<!href="|>)((?:https?|ftp):\/\/[^\s<]+)(?!<\/a>)/gim, '<a class="mosaik-link" href="$1">$1</a>');
            // Emails (simple, but decent)
            t = t.replace(/\b([a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,})\b/gim, '<a class="mosaik-link" href="mailto:$1">$1</a>');
            // Phone numbers (simple heuristic)
            // - must start with + or digit
            // - allows spaces, hyphens, parentheses
            // - at least ~9 digits total
            t = t.replace(/\b(\+?\d[\d\s\-()]{7,}\d)\b/g, '<a class="mosaik-link" href="tel:$1">$1</a>');
            return t;
        };
        // --- Block-level parsing: lists + quotes + normal lines ---
        const lines = value.split('\n');
        const out = [];
        let inUl = false;
        let inOl = false;
        let inQuote = false;
        const closeUl = () => {
            if (inUl)
                out.push('</ul>');
            inUl = false;
        };
        const closeOl = () => {
            if (inOl)
                out.push('</ol>');
            inOl = false;
        };
        const closeQuote = () => {
            if (inQuote)
                out.push('</blockquote>');
            inQuote = false;
        };
        // eslint-disable-next-line @typescript-eslint/prefer-for-of
        for (let i = 0; i < lines.length; i++) {
            const rawLine = lines[i];
            // Horizontal rule: ---, ***, or ___ (alone on a line, at least 3 chars)
            if ((/^(?:-{3,}|\*{3,}|_{3,})\s*$/).test(rawLine)) {
                closeQuote();
                closeUl();
                closeOl();
                out.push('<hr class="mosaik-hr"/>');
                continue;
            }
            // Block quote: "> " prefix
            const quoteMatch = (/^>\s+(.*)$/).exec(rawLine);
            if (quoteMatch) {
                closeUl();
                closeOl();
                if (!inQuote) {
                    out.push('<blockquote class="mosaik-quote">');
                    inQuote = true;
                }
                out.push(`${formatInline(quoteMatch[1])}<br>`);
                continue;
            }
            else {
                closeQuote();
            }
            // Bulleted list: "- " or "* " prefix
            const bulletMatch = (/^(?:-|\*)\s+(.*)$/).exec(rawLine);
            if (bulletMatch) {
                closeOl();
                if (!inUl) {
                    out.push('<ul class="mosaik-list">');
                    inUl = true;
                }
                out.push(`<li class="mosaik-listitem">${formatInline(bulletMatch[1])}</li>`);
                continue;
            }
            else {
                closeUl();
            }
            // Numbered list: "1. " / "12. " prefix
            const numberedMatch = (/^\d{1,2}\.\s+(.*)$/).exec(rawLine);
            if (numberedMatch) {
                closeUl();
                if (!inOl) {
                    out.push('<ol class="mosaik-list">');
                    inOl = true;
                }
                out.push(`<li class="mosaik-listitem">${formatInline(numberedMatch[1])}</li>`);
                continue;
            }
            else {
                closeOl();
            }
            // Normal line
            out.push(formatInline(rawLine));
            out.push('<br>');
        }
        closeQuote();
        closeUl();
        closeOl();
        let html = out.join('');
        // --- Restore protected code tokens ---
        html = html.replace(new RegExp(`${TOKEN_START}(\\d+)${TOKEN_END}`, 'g'), (_m, id) => {
            const idx = Number(id);
            return tokens[idx] ?? '';
        });
        // Small cleanup: remove trailing <br> if present
        html = html.replace(/(?:<br>)+$/g, '');
        return html;
    };
    /**
     * Formats a text into HTML using a **simplified Markdown** syntax.
     *
     * This formatter intentionally implements a pragmatic subset of Markdown that is easy to type,
     * works well in chat-/note-like UIs, and stays predictable. It is **not** a full CommonMark parser.
     *
     * ## Supported syntax
     *
     * ### Inline formatting
     * - **Bold**:
     *   - `**value**` → `<strong>value</strong>`
     *   - `__value__` → `<strong>value</strong>`
     * - *Italic*:
     *   - `*value*` → `<em>value</em>`
     *   - `_value_` → `<em>value</em>`
     * - ~~Strikethrough~~:
     *   - `~~value~~` → `<del>value</del>`
     * - `Inline code`:
     *   - `` `value` `` → `<code>value</code>`
     *
     * ### Code blocks
     * - Fenced code blocks:
     *   - <code>```multi line```</code> → `<pre><code>...</code></pre>`
     *   - The code content is HTML-escaped (e.g. `<` becomes `&lt;`) so it renders as text.
     *
     * ### Links and media
     * - Links:
     *   - `[label](https://example.com)` → `<a href="https://example.com">label</a>`
     * - Email autolinks:
     *   - `<example@example.com>` → `<a href="mailto:example@example.com">example@example.com</a>`
     * - Images:
     *   - `![alt](https://example.com/image.jpg)` → `<img src="..." alt="..."/>`
     *   - `![alt](https://example.com/image.jpg =100x20)` → `<img ... width="100" height="20"/>`
     *   - `![alt](https://example.com/image.jpg =250x)` → `<img ... width="250"/>`
     *   - `![alt](https://example.com/image.jpg =x250)` → `<img ... height="250"/>`
     *
     * ### Block-level syntax (line-based)
     * - Headers:
     *   - `# H1` through `###### H6` → `<h1>..</h1>` … `<h6>..</h6>`
     * - Blockquotes:
     *   - `> value` (multiple consecutive quote lines are grouped into a single `<blockquote>`)
     * - Lists:
     *   - Unordered list items:
     *     - `* item` or `- item` (consecutive items are grouped into one `<ul>`)
     *   - Ordered list items:
     *     - `1. item`, `2. item`, ... (consecutive items are grouped into one `<ol>`)
     *
     * ### New lines
     * - Normal text lines are separated by `<br>`.
     * - New lines inside lists and blockquotes are handled structurally (no stray `<br>` between `<li>` items).
     *
     * ## Parsing rules and limitations
     * - Parsing is intentionally **not** fully CommonMark compliant (delimiter edge-cases, nested emphasis rules, etc.).
     * - Inline formatting is applied **after** block-level parsing.
     * - Code spans / code blocks are **protected first**, so Markdown markers inside code are not interpreted.
     * - URLs inside link/image syntax are restricted to `http(s)://` for simplicity.
     *
     * ## Security note
     * This formatter produces HTML. If `value` is user-generated and you render the result via `innerHTML`,
     * you **must** ensure the output is safe (e.g. sanitize/encode appropriately) to prevent XSS.
     *
     * @public
     */
    TextFormatters.MARKDOWN = (input) => {
        if (!input)
            return '';
        // Normalize line endings
        let value = input.replace(/\r\n/g, '\n');
        const escapeHtml = (s) => s
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#39;');
        // --- Protect code blocks and inline code first ---
        const TOKEN_START = '\uE000';
        const TOKEN_END = '\uE001';
        const tokens = [];
        const putToken = (html) => {
            const id = tokens.length;
            tokens.push(html);
            return `${TOKEN_START}${id}${TOKEN_END}`;
        };
        // Fenced code blocks: ``` ... ```
        value = value.replace(/```([\s\S]*?)```/g, (_m, code) => {
            return putToken(`<pre><code>${escapeHtml(code)}</code></pre>`);
        });
        // Inline code: `...` (no newlines)
        value = value.replace(/`([^`\n]+?)`/g, (_m, code) => {
            return putToken(`<code>${escapeHtml(code)}</code>`);
        });
        // --- Inline formatting (runs on normal text lines + list/quote items) ---
        const formatInline = (text) => {
            let t = text;
            // Images (optional =WxH | =Wx | =xH) - IMPORTANT: do NOT escape "="
            t = t
                .replace(/!\[([^\]]*)\]\((https?:\/\/[^)\s]+)\s*=\s*(\d+)x(\d+)\)/g, '<img src="$2" alt="$1" width="$3" height="$4" />')
                .replace(/!\[([^\]]*)\]\((https?:\/\/[^)\s]+)\s*=\s*(\d+)x\)/g, '<img src="$2" alt="$1" width="$3" />')
                .replace(/!\[([^\]]*)\]\((https?:\/\/[^)\s]+)\s*=\s*x(\d+)\)/g, '<img src="$2" alt="$1" height="$3" />')
                .replace(/!\[([^\]]*)\]\((https?:\/\/[^)\s]+)\)/g, '<img src="$2" alt="$1" />');
            // Links: [text](url)
            t = t.replace(/\[([^\]]*)\]\((https?:\/\/[^)]+)\)/g, '<a href="$2">$1</a>');
            // Email autolink: <a@b.com>
            t = t.replace(/<([a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,})>/gi, '<a href="mailto:$1">$1</a>');
            // Strikethrough: ~~value~~
            t = t.replace(/~~([\s\S]*?)~~/g, '<del>$1</del>');
            // Bold: **value** or __value__
            t = t
                .replace(/\*\*([\s\S]*?)\*\*/g, '<strong>$1</strong>')
                .replace(/__([\s\S]*?)__/g, '<strong>$1</strong>');
            // Italic: *value* or _value_
            // Avoid eating list markers "* " and reduce word-internal underscore collisions.
            t = t
                .replace(/(^|[^\w*])\*([^\s][\s\S]*?[^\s])\*(?!\w)/g, '$1<em>$2</em>')
                .replace(/(^|[^\w_])_([^\s][\s\S]*?[^\s])_(?!\w)/g, '$1<em>$2</em>');
            return t;
        };
        // --- Block parsing (line-based) ---
        const lines = value.split('\n');
        const out = [];
        let inUl = false;
        let inOl = false;
        let inQuote = false;
        const closeUl = () => {
            if (inUl)
                out.push('</ul>');
            inUl = false;
        };
        const closeOl = () => {
            if (inOl)
                out.push('</ol>');
            inOl = false;
        };
        const closeQuote = () => {
            if (inQuote)
                out.push('</blockquote>');
            inQuote = false;
        };
        for (const raw of lines) {
            // Headers: # ... ######
            const h = (/^(#{1,6})\s+(.*)$/).exec(raw);
            if (h) {
                closeQuote();
                closeUl();
                closeOl();
                const level = h[1].length;
                out.push(`<h${level}>${formatInline(h[2])}</h${level}>`);
                continue;
            }
            // Blockquote: > ...
            const q = (/^>\s?(.*)$/).exec(raw);
            if (q) {
                closeUl();
                closeOl();
                if (!inQuote) {
                    out.push('<blockquote>');
                    inQuote = true;
                }
                out.push(`${formatInline(q[1])}<br>`);
                continue;
            }
            else {
                closeQuote();
            }
            // Unordered list: "* item" or "- item"
            const ul = (/^(?:\*|-)\s+(.*)$/).exec(raw);
            if (ul) {
                closeOl();
                if (!inUl) {
                    out.push('<ul>');
                    inUl = true;
                }
                out.push(`<li>${formatInline(ul[1])}</li>`);
                continue;
            }
            else {
                closeUl();
            }
            // Ordered list: "1. item"
            const ol = (/^\d+\.\s+(.*)$/).exec(raw);
            if (ol) {
                closeUl();
                if (!inOl) {
                    out.push('<ol>');
                    inOl = true;
                }
                out.push(`<li>${formatInline(ol[1])}</li>`);
                continue;
            }
            else {
                closeOl();
            }
            // Normal line
            out.push(formatInline(raw));
            out.push('<br>');
        }
        closeQuote();
        closeUl();
        closeOl();
        let html = out.join('').replace(/(?:<br>)+$/g, '');
        // Restore code tokens (kept HTML-escaped inside)
        html = html.replace(new RegExp(`${TOKEN_START}(\\d+)${TOKEN_END}`, 'g'), (_m, id) => {
            const idx = Number(id);
            return tokens[idx] ?? '';
        });
        // Remove trailing <br> inside blockquotes (if any)
        html = html.replace(/<blockquote>([\s\S]*?)<br>\s*<\/blockquote>/g, '<blockquote>$1</blockquote>');
        return html;
    };
    /**
     * Formats a text into HTML using a **BBCode-like** syntax.
     *
     * This formatter replaces common BBCode tags with their HTML equivalents.
     * It aims to be practical and predictable for UI rendering (forums/chat-like content),
     * not to implement every edge-case of every BBCode dialect.
     *
     * ## Supported tags
     *
     * ### Text formatting
     * - Bold: `[b]value[/b]` → `<strong>value</strong>`
     * - Italic: `[i]value[/i]` → `<em>value</em>`
     * - Underline: `[u]value[/u]` → `<u>value</u>`
     * - Strikethrough: `[s]value[/s]` → `<del>value</del>`
     *
     * ### Code
     * - Code block: `[code]value[/code]` → `<pre><code>value</code></pre>`
     *   - The code content is HTML-escaped, so `<` etc. render as text.
     *   - Code blocks are protected first, so other BBCode tags inside are not interpreted.
     *
     * ### Links & media
     * - URL:
     *   - `[url=http://example.com]label[/url]` → `<a href="http://example.com">label</a>`
     *   - `[url]http://example.com[/url]` → `<a href="http://example.com">http://example.com</a>`
     * - Image:
     *   - `[img]http://example.com/a.jpg[/img]` → `<img src="..." alt=""/>`
     *   - `[img width=100 height=20]http://...[/img]` → `<img src="..." width="100" height="20" />`
     *   - `[img width=250]http://...[/img]` → `<img src="..." width="250" />`
     *   - `[img height=250]http://...[/img]` → `<img src="..." height="250" />`
     * - Email:
     *   - `[email]a@b.com[/email]` → `<a href="mailto:a@b.com">a@b.com</a>`
     *
     * ### Styling
     * - Color:
     *   - `[color=red]value[/color]` → `<span style="color:red;">value</span>`
     * - Size:
     *   - `[size=1]value[/size]` → `<span style="font-size:1em;">value</span>`
     *     (Value is treated as `em` for simplicity.)
     *
     * ### Blocks
     * - Quote:
     *   - `[quote]value[/quote]` → `<blockquote>value</blockquote>`
     * - Lists:
     *   - `[list][*]a[*]b[/list]` → `<ul><li>a</li><li>b</li></ul>`
     *   - `[list=1][*]a[*]b[/list]` → `<ol><li>a</li><li>b</li></ol>`
     *   - Items are recognized via `[*]` (no closing tag required).
     *
     * ### New lines
     * - Remaining new lines are converted to `<br>`.
     * - New lines inside generated `<ul>/<ol>/<blockquote>/<pre>` are handled structurally
     *   to avoid invalid markup like `<ul>...<br><li>...</li>...</ul>`.
     *
     * ## Security note
     * This formatter outputs HTML. If the input is user-generated and the output is rendered
     * via `innerHTML`, sanitize the output HTML to prevent XSS.
     *
     * @public
     */
    TextFormatters.BBCODE = (input) => {
        if (!input)
            return '';
        // Normalize line endings
        let value = input.replace(/\r\n/g, '\n');
        const escapeHtml = (s) => s
            .replace(/&/g, '&amp;')
            .replace(/</g, '&lt;')
            .replace(/>/g, '&gt;')
            .replace(/"/g, '&quot;')
            .replace(/'/g, '&#39;');
        // Tokenization to protect blocks that must not be post-processed (e.g. code, lists, quotes)
        const TOKEN_START = '\uE000';
        const TOKEN_END = '\uE001';
        const tokens = [];
        const putToken = (html) => {
            const id = tokens.length;
            tokens.push(html);
            return `${TOKEN_START}${id}${TOKEN_END}`;
        };
        // --- 1) Protect [code]...[/code] first ---
        value = value.replace(/\[code\]([\s\S]*?)\[\/code\]/gi, (_m, code) => {
            return putToken(`<pre><code>${escapeHtml(code)}</code></pre>`);
        });
        // --- Helper: inline replacements (safe-ish order) ---
        const formatInline = (text) => {
            let t = text;
            // URL with label first
            t = t.replace(/\[url=([^\]]+)\]([\s\S]*?)\[\/url\]/gi, '<a href="$1">$2</a>');
            // URL bare
            t = t.replace(/\[url\]([\s\S]*?)\[\/url\]/gi, '<a href="$1">$1</a>');
            // Email
            t = t.replace(/\[email\]([\s\S]*?)\[\/email\]/gi, '<a href="mailto:$1">$1</a>');
            // Images (attribute variants first)
            t = t
                .replace(/\[img\s+width=(\d+)\s+height=(\d+)\](http[s]?:\/\/[\s\S]*?)\[\/img\]/gi, '<img src="$3" width="$1" height="$2" />')
                .replace(/\[img\s+width=(\d+)\](http[s]?:\/\/[\s\S]*?)\[\/img\]/gi, '<img src="$2" width="$1" />')
                .replace(/\[img\s+height=(\d+)\](http[s]?:\/\/[\s\S]*?)\[\/img\]/gi, '<img src="$2" height="$1" />')
                .replace(/\[img\]([\s\S]*?)\[\/img\]/gi, '<img src="$1" alt=""/>');
            // Color / size
            t = t.replace(/\[color=([^\]]+)\]([\s\S]*?)\[\/color\]/gi, '<span style="color:$1;">$2</span>');
            t = t.replace(/\[size=([^\]]+)\]([\s\S]*?)\[\/size\]/gi, '<span style="font-size:$1em;">$2</span>');
            // Basic formatting
            t = t
                .replace(/\[b\]([\s\S]*?)\[\/b\]/gi, '<strong>$1</strong>')
                .replace(/\[i\]([\s\S]*?)\[\/i\]/gi, '<em>$1</em>')
                .replace(/\[u\]([\s\S]*?)\[\/u\]/gi, '<u>$1</u>')
                .replace(/\[s\]([\s\S]*?)\[\/s\]/gi, '<del>$1</del>');
            return t;
        };
        // --- 2) Parse [list]...[/list] and [list=1]...[/list] as structural HTML and protect them ---
        const renderList = (body, ordered) => {
            // Split by [*] markers; BBCode typically doesn't require [/*]
            const rawItems = body
                .split(/\[\*\]/g)
                .map((x) => x.trim())
                .filter((x) => x.length > 0);
            const tag = ordered ? 'ol' : 'ul';
            const itemsHtml = rawItems
                .map((item) => {
                // Allow inline formatting inside list items
                const content = formatInline(item).replace(/\n/g, '<br>');
                return `<li>${content}</li>`;
            })
                .join('');
            return `<${tag}>${itemsHtml}</${tag}>`;
        };
        // Ordered list: [list=1]...[/list]
        value = value.replace(/\[list=1\]([\s\S]*?)\[\/list\]/gi, (_m, body) => {
            return putToken(renderList(body, true));
        });
        // Unordered list: [list]...[/list]
        value = value.replace(/\[list\]([\s\S]*?)\[\/list\]/gi, (_m, body) => {
            return putToken(renderList(body, false));
        });
        // --- 3) Parse [quote]...[/quote] as a structural block and protect it ---
        value = value.replace(/\[quote\]([\s\S]*?)\[\/quote\]/gi, (_m, body) => {
            // Allow inline formatting and keep line breaks inside quote
            const inner = formatInline(body).replace(/\n/g, '<br>');
            return putToken(`<blockquote>${inner}</blockquote>`);
        });
        // --- 4) Remaining inline tags in the rest of the text ---
        value = formatInline(value);
        // --- 5) New lines -> <br> (safe because blocks/lists/quotes/code are already tokenized) ---
        value = value.replace(/\n/g, '<br>');
        // --- 6) Restore tokens ---
        value = value.replace(new RegExp(`${TOKEN_START}(\\d+)${TOKEN_END}`, 'g'), (_m, id) => {
            const idx = Number(id);
            return tokens[idx] ?? '';
        });
        // Cleanup: trim trailing <br>
        value = value.replace(/(?:<br>)+$/g, '');
        return value;
    };
})(TextFormatters || (TextFormatters = {}));
//# sourceMappingURL=TextFormatter.js.map