Help us shape the future of Go! Take the 2026 Go Developer Survey

petroglyph

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Oct 18, 2026 License: MIT Imports: 22 Imported by: 1

README

petroglyph

A Go Markdown-to-HTML renderer built on goldmark. One function call turns an untrusted Markdown document into sanitized HTML with GitHub-style extras. No configuration required.

Features

  • GitHub-flavored Markdown: tables, strikethrough, task lists, autolinks, footnotes, and emoji (:tada:).
  • Heading ids with permalink anchors, and explicit ids like ## Heading {#custom-id}.
  • GitHub alerts: > [!NOTE], [!TIP], [!IMPORTANT], [!WARNING], [!CAUTION], with titles.
  • Code fences highlighted by chroma with CSS classes, using the github style.
  • Mermaid fences rendered as <pre class="mermaid"> for your browser-side mermaid library.
  • Math with $...$, $$...$$, \(...\), and \[...\], converted to MathJax delimiters.
  • YAML front matter rendered as a table above the document.
  • Sized images: ![alt](https://example.com/img.png =800x600).
  • Raw HTML passes through a sanitizer policy modeled on GitHub's subset.

Install

go get github.com/brutasse/petroglyph

Usage

import "github.com/brutasse/petroglyph"

html, flags := petroglyph.Convert(source)

Convert renders the whole document: optional front matter, body, sanitized raw HTML, wrapped tables, and alert titles. On a render failure it returns the source as escaped <pre> text instead of failing.

The returned Flags tell you which optional scripts the page needs:

if flags.Math {
    // load MathJax
}
if flags.Mermaid {
    // load mermaid
}

This keeps pages free of JavaScript they do not use.

Lower-level API
  • petroglyph.GFM is a goldmark.Extender. Compose it into your own goldmark pipeline when you want control over parsing or rendering. You then sanitize the output yourself.
  • petroglyph.New() returns a goldmark instance with the extension applied. Use it with petroglyph.Needs(doc, source) when you already hold the parsed document.
  • petroglyph.DisplayPolicy() returns the bluemonday policy Convert applies. Reuse it to sanitize other markup the same way.

Styling the output

Convert emits these classes. Your stylesheet decides how they look; the library ships no CSS.

Markup Meaning
.table-wrap wrapper div around every table, for overflow-x: auto
.frontmatter table generated from YAML front matter
.codeblock wrapper div around a highlighted code fence
.chroma chroma-generated code markup (class-based)
.mermaid <pre> holding a mermaid diagram source
.markdown-alert .markdown-alert-note and friends alert blockquotes
.markdown-alert-title title paragraph inside an alert
.heading-anchor the # permalink link inside a heading
.fallback <pre> used when rendering failed

Generate the chroma stylesheet once with the same style the formatter uses:

f := chromahtml.New(chromahtml.WithClasses(true))
css, _ := os.Create("chroma.css")
defer css.Close()
f.WriteCSS(css, styles.Get("github"))

showcase.md exercises every feature. Render it with Convert to inspect the full markup, or use it as a fixture in your own stylesheet work.

Math and mermaid

Math output uses the \(...\) and \[...\] delimiters, which MathJax activates by default. A page shows math by loading MathJax when Flags.Math is set. A page shows diagrams by loading mermaid with startOnLoad: true when Flags.Mermaid is set.

Safety

Convert renders raw HTML (goldmark unsafe mode) and then filters the result through DisplayPolicy. The policy extends bluemonday's UGC policy with the classes, ids, and checkbox inputs this renderer generates. Treat the output as display-safe, not script-safe: it can carry class and id attributes, so do not serve your own trust-critical DOM ids that a document could collide with.

License

MIT. See LICENSE.

Documentation

Overview

Package petroglyph is a Markdown-to-HTML stack: a zero-config goldmark extension assembling GitHub-flavored Markdown (tables, strikethrough, task lists, autolinks, footnotes, emoji) plus heading ids and permalink anchors, GitHub alerts, `![alt](url =WxH)` image sizing, chroma-highlighted and mermaid fences, YAML front matter, and MathJax math in $...$, $$...$$, \(...\), \[...\] delimiters. Raw HTML passes through the renderer for DisplayPolicy to gate, GitHub-style.

Convert is the intended entry point. The GFM extender alone composes into a custom goldmark pipeline, but then raw-HTML rendering and sanitizing are the caller's business.

Index

Constants

This section is empty.

Variables

View Source
var GFM goldmark.Extender = gfmExt{}

GFM extends a goldmark instance with the full feature set and no configuration.

Functions

func AddAlertTitles

func AddAlertTitles(html string) string

AddAlertTitles injects the GitHub title paragraph (octicon + label) as the first child of every alert blockquote. Callers apply it to sanitized output: the markup is this file's, never content's, so the sanitizer's GitHub raw-HTML subset — which rejects svg — stays intact.

func DisplayPolicy

func DisplayPolicy() *bluemonday.Policy

DisplayPolicy renders untrusted content safely. Chroma emits class-named spans/tables and mermaid fences need a class; UGC strips class by default, so allow it back — no user-controlled CSS is ever served, classes only map to the fixed stylesheets the app ships.

func New

func New() goldmark.Markdown

New returns a goldmark instance with the GFM extension applied.

func SplitFrontMatter

func SplitFrontMatter(src string) (string, string)

SplitFrontMatter consumes a leading YAML front-matter block ("---" line to "---" or "..." line). It returns the table markup plus remaining source; when the block is absent or the top level is not a scalar-keyed mapping, the source passes through untouched with an empty table. Values that are nested collections render as compact inline values instead of a rejection.

This runs as a source pass before goldmark, not as an extension: an invalid front-matter block must fall through to normal Markdown parsing, and by the time any transformer or block parser could inspect it, the "---" delimiters are already thematic breaks or setext heading underlines. Convert applies it; callers running the GFM extender on their own pipeline must call it first, or front matter parses as a setext heading.

Types

type Flags

type Flags struct {
	Math    bool // TeX math present: load MathJax
	Mermaid bool // mermaid fence present: load mermaid
}

Flags tells the page which optional payloads the rendered HTML needs: the template loads only the vendored JS actually required.

func Convert

func Convert(src string) (string, Flags)

Convert renders a whole Markdown document: the optional YAML front matter table, then the body with raw HTML gated by DisplayPolicy, every table wrapped for horizontal scrolling, and alert titles injected (trusted markup, post-sanitize). On render failure it returns the source as escaped preformatted text.

func Needs

func Needs(doc ast.Node, source []byte) Flags

Needs reports whether the parsed document contains math or mermaid.

Jump to

Keyboard shortcuts

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