(integrations)= # Integrations ```{rst-class} lead Build application-level Markdown pipelines with a reusable Wenmode instance, safe user-content defaults, generated heading IDs, table-of-contents output, AST export, and streaming previews. ``` --- Use this page when you are wiring Wenmode into an application rather than trying one API call. The examples keep parser setup, rendering policy, and post-processing in one place so the behavior is easy to test. ## Reuse one configured instance Create a small service object around the rule set your product supports. A `Wenmode` instance can be reused across calls; render state is created per render operation. ```python from wenmode import Wenmode from wenmode.presets import github class MarkdownService: def __init__(self, wenmode: Wenmode | None = None) -> None: self.wenmode = wenmode if wenmode is not None else Wenmode(github) def render_comment(self, text: str) -> str: return self.wenmode.render(text) service = MarkdownService() text = ''' - [x] ship docs Visit https://example.com ''' html = service.render_comment(text) assert '' in html assert 'https://example.com' in html ``` ## Render untrusted user content For comments, profile fields, forum posts, and other user-authored Markdown, start with the default HTML renderer. It escapes raw HTML and removes unsafe link targets. ```python from wenmode import Wenmode from wenmode.presets import github wenmode = Wenmode(github) text = ''' Hello . [bad](javascript:alert(1)) ''' html = wenmode.render(text) assert '<script>alert(1)</script>' in html assert 'bad' in html assert 'javascript:alert' not in html ``` If your application also wants raw HTML syntax to stay as plain text in the AST, remove the raw HTML parser rules as shown in {ref}`recipes`. ## Publish documentation pages Documentation sites often need the rendered body, a table of contents, and a machine-readable AST for search or indexing. Parse once, then run tree transforms before rendering. ```python import json from wenmode import HTMLRenderer, Wenmode from wenmode.headings import Slugger, add_heading_ids from wenmode.toc import collect_toc, render_toc_html class RenderedPage: def __init__(self, html: str, toc_html: str, ast_json: str) -> None: self.html = html self.toc_html = toc_html self.ast_json = ast_json def render_page(source: str) -> RenderedPage: root = Wenmode().parse(source) add_heading_ids(root, slugger=Slugger(), min_depth=2) toc = collect_toc(root, min_depth=2, max_depth=3) toc_html = render_toc_html(toc) body_html = HTMLRenderer().render(root) return RenderedPage( html=toc_html + body_html, toc_html=toc_html, ast_json=json.dumps(root.to_ast(), ensure_ascii=False), ) text = ''' # Guide ## Install Run **wenmode**. ''' page = render_page(text) assert 'Install' in page.toc_html assert '

Install

' in page.html assert '"type": "root"' in page.ast_json ``` ## Stream low-latency previews Use the `streaming` preset for live previews, chat responses, or other views that should emit HTML chunks before the whole document is available. Keep reference-style links, footnotes, and other deferred features out of this path. ```python from collections.abc import Iterable from wenmode import Wenmode from wenmode.presets import streaming preview = Wenmode(streaming) def render_preview(lines: Iterable[str]) -> Iterable[str]: yield '
\n' yield from preview.stream(lines) yield '
\n' chunks = list( render_preview( [ '# Preview\n', '\n', 'A [link](https://example.com).\n', ] ) ) html = ''.join(chunks) assert html.startswith('
') assert '

Preview

' in html assert 'link' in html ``` See {ref}`rule-matrix` for rules that are not compatible with streaming. ## Package a product dialect When multiple services need the same Markdown behavior, keep the rule list in one application module and import that module everywhere. This avoids subtle differences between the editor preview, API rendering, background jobs, and test fixtures. ```python from wenmode import Wenmode from wenmode.presets import commonmark from wenmode.rules import HtmlBlock, RawHtml product_rules = [rule for rule in commonmark if rule not in {HtmlBlock, RawHtml}] product_markdown = Wenmode(product_rules) text = 'plain text in our dialect' expected = '''

<span>plain text in our dialect</span>

''' html = product_markdown.render(text) assert html == expected.lstrip() ``` For new syntax, add a parser rule and renderer handlers together. See {ref}`custom-rules` for an RST-inspired example that creates a new node type and registers HTML, Markdown, and RST rendering behavior.