benmark

package module
v0.1.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 9, 2026 License: MIT Imports: 27 Imported by: 0

README

benmark — a robust, batteries-included Markdown renderer for Go

Go Reference Go Report Card

benmark turns Markdown into safe, styled HTML in one Go import. It is a batteries-included distribution built on goldmark: CommonMark + GitHub-Flavored Markdown, plus syntax highlighting, Mermaid diagrams, media embeds (video / audio / PDF / YouTube / Vimeo), heading anchors, wikilinks, and front matter — sanitized by default so the output is safe to drop straight into innerHTML.

Think of it as pip install markdown for Go, except it also ships the CSS and the client-side hydration for diagrams and embeds.

import "github.com/benmore-studio/benmark"

html, err := benmark.RenderString("# Hello\n\nSome **markdown** with a ```mermaid``` diagram.")

Why benmark

Most Go Markdown libraries give you a parser and stop there — you still wire up highlighting, sanitization, a theme, and client rendering yourself, and every project re-derives the same glue. benmark is the glue, done once and safely:

  • Correct — CommonMark + GFM via goldmark (the parser Hugo uses).
  • Rich — tables, task lists, footnotes, definition lists, strikethrough, autolinks, wikilinks, front matter, and :emoji: shortcodes.
  • Callouts — GitHub-style > [!NOTE] / [!TIP] / [!WARNING] / [!IMPORTANT] / [!CAUTION] alerts, styled by the theme.
  • Diagrams```mermaid fences become hydration hooks rendered by mermaid.js on the client.
  • Highlighted — fenced code is syntax-highlighted with chroma (class-based; ship CSS()), with a copy button added by HydrateJS().
  • Media — images (incl. inline data: images) and bare URLs that point at .mp4/.mp3/.pdf, or at YouTube/Vimeo, become <video>/<audio>/ <iframe> embeds.
  • Safe by default — output is sanitized with bluemonday; scripts, inline event handlers, and javascript:/data: URLs never survive.
  • StyledCSS() returns a self-contained, light/dark-aware stylesheet.
  • BatteriesHydrateJS() renders diagrams client-side after insertion.

Install

go get github.com/benmore-studio/benmark

Usage

One-shot
html, err := benmark.RenderString(src) // sanitized HTML, default config
r := benmark.New(
    benmark.WithHighlightTheme("github"),
    benmark.WithMediaEmbeds(true),
)
html, err := r.Render([]byte(src))
Front matter
doc, _ := benmark.New().RenderDoc([]byte("---\ntitle: Hi\n---\n# Body"))
doc.HTML          // rendered body (front matter stripped)
doc.Meta["title"] // "Hi"
Serve the theme + hydration
mux.HandleFunc("GET /markdown.css", func(w http.ResponseWriter, _ *http.Request) {
    w.Header().Set("Content-Type", "text/css")
    io.WriteString(w, benmark.CSS())
})
mux.HandleFunc("GET /markdown-hydrate.js", func(w http.ResponseWriter, _ *http.Request) {
    w.Header().Set("Content-Type", "application/javascript")
    io.WriteString(w, benmark.HydrateJS())
})

Wrap the rendered HTML in class="benmark", include markdown.css, load mermaid.js, and call hydrate(el) after inserting the HTML.

Inline / chat mode
// One-line messages stay inline (no wrapping <p>, newlines become <br>).
html, _ := benmark.RenderString(msg, benmark.WithInline(true))

Options

Option Default Effect
WithSanitize(bool) on bluemonday allowlist over the output
WithHighlightTheme(string) "github" chroma style; "" disables
WithHeadingAnchors(bool) on heading ids + anchors
WithMermaid(bool) on ```mermaid<pre class="mermaid">
WithMediaEmbeds(bool) on video / audio / PDF / YouTube / Vimeo
WithWikilinks(bool) on [[Page]] links
WithEmoji(bool) on :tada: → 🎉 shortcodes
WithFrontmatter(bool) on parse + strip YAML/TOML front matter
WithInline(bool) off single-line "chat" subset
WithEmbedHosts(...string) YouTube+Vimeo iframe host allowlist

Security

Output is sanitized by default and is safe for innerHTML. <script>, inline event handlers (onerror, onclick, …), and dangerous URL schemes (javascript:, data:, vbscript:) are removed. <iframe> is pinned to YouTube/Vimeo player URLs and PDF documents. Only disable sanitization (WithSanitize(false)) for first-party Markdown you fully trust.

License

MIT — see LICENSE. benmark builds on goldmark, chroma, bluemonday, and the goldmark extensions by Abhinav Gupta; see NOTICE.

Documentation

Overview

Package benmark renders Markdown to safe, styled HTML.

It is a batteries-included distribution built on goldmark: CommonMark + GitHub-Flavored Markdown (tables, task lists, strikethrough, autolinks), plus syntax highlighting, Mermaid diagrams, media embeds (video / audio / PDF / YouTube / Vimeo), heading anchors, wikilinks, and front matter — all sanitized by default so the output is safe to assign to innerHTML.

The zero-config path:

html, err := benmark.RenderString("# Hello\n\nSome **markdown**.")

For repeated rendering, build a Renderer once and reuse it (it is safe for concurrent use):

r := benmark.New(benmark.WithHighlightTheme("github"))
html, err := r.Render(src)

Diagrams and math-like rich content are emitted as hydration hooks (e.g. <pre class="mermaid">) and rendered on the client; pair the output with CSS() and HydrateJS() to get styling and client-side rendering.

Index

Constants

This section is empty.

Variables

View Source
var DefaultEmbedHosts = []string{
	"youtube.com", "www.youtube.com", "youtube-nocookie.com",
	"youtu.be", "vimeo.com", "player.vimeo.com",
}

DefaultEmbedHosts is the iframe host allowlist used when Options.EmbedHosts is empty. Only these hosts are turned into <iframe> embeds; every other host is left as an ordinary link.

Functions

func CSS

func CSS() string

CSS returns a self-contained stylesheet for benmark output, including the syntax-highlighting rules for the default "github" style. Wrap rendered HTML in an element with class="benmark".

func CSSForStyle

func CSSForStyle(style string) string

CSSForStyle is CSS with syntax-highlighting rules for a specific chroma style (e.g. "monokai", "dracula"). Unknown names fall back to a default.

func HydrateJS

func HydrateJS() string

HydrateJS returns the client hydration script (an ES module exporting `hydrate`) that renders Mermaid diagrams in benmark output. Serve it and call hydrate() after inserting rendered HTML into the DOM.

func Render

func Render(src []byte, opts ...Option) (template.HTML, error)

Render renders Markdown to sanitized HTML with the default configuration. For custom options or hot paths, build a Renderer with New and reuse it.

func RenderString

func RenderString(src string, opts ...Option) (string, error)

RenderString is Render for string in/out.

Types

type Document

type Document struct {
	HTML template.HTML
	Meta map[string]any
}

Document is the result of RenderDoc: the rendered HTML plus any front matter metadata parsed from the source.

type Option

type Option func(*Options)

Option mutates Options. Passed to New / Render / RenderString.

func WithEmbedHosts

func WithEmbedHosts(hosts ...string) Option

WithEmbedHosts overrides the iframe host allowlist for MediaEmbeds.

func WithEmoji

func WithEmoji(on bool) Option

WithEmoji toggles :shortcode: emoji.

func WithFrontmatter

func WithFrontmatter(on bool) Option

WithFrontmatter toggles front matter parsing/stripping.

func WithHeadingAnchors

func WithHeadingAnchors(on bool) Option

WithHeadingAnchors toggles heading ids + anchors.

func WithHighlightTheme

func WithHighlightTheme(style string) Option

WithHighlightTheme sets the chroma style (empty disables highlighting).

func WithInline

func WithInline(on bool) Option

WithInline enables the single-line "chat" rendering subset.

func WithMediaEmbeds

func WithMediaEmbeds(on bool) Option

WithMediaEmbeds toggles video/audio/PDF/YouTube/Vimeo embeds.

func WithMermaid

func WithMermaid(on bool) Option

WithMermaid toggles ```mermaid hydration hooks.

func WithSanitize

func WithSanitize(on bool) Option

WithSanitize toggles output sanitization. Only turn it OFF for trusted, first-party Markdown you control end to end.

func WithWikilinks(on bool) Option

WithWikilinks toggles [[Page]] links.

type Options

type Options struct {
	// Sanitize runs the rendered HTML through the bluemonday allowlist.
	// Keep this ON (the default) whenever the output is untrusted — it is
	// the security boundary that makes the result safe for innerHTML.
	Sanitize bool

	// Inline renders the "chat subset": newlines become <br> and a single
	// wrapping <p> is stripped, so a one-line message stays inline instead
	// of becoming a block paragraph.
	Inline bool

	// HighlightTheme is the chroma style used for fenced code blocks
	// (e.g. "github", "monokai"). Empty disables syntax highlighting.
	// Highlighted spans are class-based; ship CSS() so they are styled.
	HighlightTheme string

	// HeadingAnchors adds an id to every heading and a linkable anchor.
	HeadingAnchors bool

	// Mermaid turns “`mermaid fences into <pre class="mermaid"> hydration
	// hooks (rendered client-side by HydrateJS + mermaid.js).
	Mermaid bool

	// MediaEmbeds turns image tags and bare URLs that point at media into
	// <video>/<audio>/<iframe> embeds. See embeds.go for the rules.
	MediaEmbeds bool

	// Wikilinks enables [[Page Name]] internal links.
	Wikilinks bool

	// Emoji enables :shortcode: emoji (e.g. :tada: → 🎉).
	Emoji bool

	// Frontmatter strips a leading YAML/TOML front matter block from the
	// body and (via RenderDoc) exposes it as metadata.
	Frontmatter bool

	// EmbedHosts is the allowlist of iframe hosts for MediaEmbeds. Empty
	// uses DefaultEmbedHosts (YouTube + Vimeo).
	EmbedHosts []string
}

Options controls what benmark renders and how. Use the With* Option helpers with New/Render rather than constructing this directly, so future fields keep sensible defaults.

func DefaultOptions

func DefaultOptions() Options

DefaultOptions is the batteries-included configuration: full document rendering, sanitized, with every extension enabled.

type Renderer

type Renderer struct {
	// contains filtered or unexported fields
}

Renderer is a reusable, concurrency-safe Markdown renderer. Build one with New and call Render/RenderString/RenderDoc as many times as you like.

func New

func New(opts ...Option) *Renderer

New builds a Renderer from DefaultOptions overlaid with opts.

func (*Renderer) CSS

func (r *Renderer) CSS() string

CSS returns the stylesheet matching this renderer's highlight theme.

func (*Renderer) Render

func (r *Renderer) Render(src []byte) (template.HTML, error)

Render renders Markdown source to sanitized HTML.

func (*Renderer) RenderDoc

func (r *Renderer) RenderDoc(src []byte) (*Document, error)

RenderDoc renders Markdown and returns the HTML plus front matter metadata (nil Meta when Frontmatter is disabled or absent).

func (*Renderer) RenderString

func (r *Renderer) RenderString(src string) (string, error)

RenderString is Render for string in/out.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL