From cd7efb09c3ea2713cc3cea0fbcde9ce0b7a0fa06 Mon Sep 17 00:00:00 2001 From: mhenrixon Date: Fri, 3 Jul 2026 08:57:26 +0200 Subject: [PATCH] =?UTF-8?q?feat(page):=20DocsUI::Markdown=20=E2=80=94=20GF?= =?UTF-8?q?M=20markdown=20islands=20for=20prose=20authoring?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Prose is the most-written doc content and the noisiest to hand-build from p/code/plain calls. Ship DocsUI::Markdown: authors write a block of GFM and it renders styled identically to DocsUI::Prose, with fenced code routed through DocsUI::Code (Rouge). It parses GFM with commonmarker (v2, comrak) and walks the AST emitting Phlex nodes — it never `raw`s commonmarker's HTML. That gives Phlex-native escaping (no html_safe on author text — Critical Rule 7; #{} renders literally), fenced code delegated to DocsUI::Code, GFM tables with the kit's table classes, and the exact Prose typography classes on the wrapper. - DocsUI::Page gains `md(source)` — a lowercase method so `md <<~MD … MD` needs no parens (unlike Prose()/Example()). - Raw HTML is dropped (html_block/html_inline AST nodes skipped) — no after.") + + # The executable tag is dropped (AST html_inline nodes are skipped). The + # inner text may remain as inert, escaped text — but never as a live tag. + expect(html).not_to include("") + expect(html).to include("Before") + expect(html).to include("after") + end + + it "drops a raw HTML block entirely" do + html = render_md("Text.\n\n
boom
") + + expect(html).not_to include("
D") + + expect(html).to include("<") + expect(html).to include(">") + expect(html).to include("&") + end + + it "renders an empty wrapper for nil or empty source (never raises)" do + expect { described_class.new(nil).call }.not_to raise_error + expect(described_class.new("").call).to include("
") + end + + it "normalizes a non-UTF-8 source (commonmarker requires UTF-8)" do + ascii = "Plain ASCII prose.".encode(Encoding::US_ASCII) + + expect { render_md(ascii) }.not_to raise_error + expect(render_md(ascii)).to include("Plain ASCII prose.") + end + + it "renders a header-only table without a body (no drop error)" do + html = render_md("| a | b |\n|---|---|") + + expect(html).to include("markdown") + end + end +end