Goldmark Markdown parser

CommonMark-compliant markdown parser backed by yuin/goldmark. It parses .md content into a Piko-native AST (*markdown_ast.Document) and extracts YAML frontmatter as a map[string]any.

Overview

The Goldmark parser is opt-in. Pass it through piko.WithMarkdownParser and the collection service registers a markdown content provider that parses .md files with it. Without that option, the collection service skips the markdown provider and leaves .md files unparsed.

Every parser instance carries a fixed core extension set: GitHub-Flavoured Markdown, tables, strikethrough, task lists, autolinks, footnotes, YAML frontmatter via yuin/goldmark-meta, and stefanfritsch/goldmark-fences for fenced container blocks (::: warning, ::: note). Heading IDs auto-generate. The parser reads heading attribute syntax, so # Heading {#custom-id} carries its id into the Piko AST. The parser reads only the id attribute and drops a .class attribute.

Parse runs Goldmark's parser, extracts frontmatter from the parser context, and walks the resulting Goldmark AST into Piko-native nodes. Each call creates a fresh parser context, so a single parser instance is stateless across calls and safe to share across concurrent collection processing.

NewParser takes a variadic list of Goldmark extenders, not a config struct: NewParser(extensions ...goldmark.Extender). Pass extra extenders, for example a Chroma-backed code highlighter, MathJax, or Mermaid. The parser appends them to the built-in set with no Piko-specific glue.

Configuration

import (
    "github.com/yuin/goldmark"
    highlighting "github.com/yuin/goldmark-highlighting/v2"
    "piko.sh/piko/wdk/markdown/markdown_provider_goldmark"
)

parser := markdown_provider_goldmark.NewParser(
    highlighting.NewHighlighting(
        highlighting.WithStyle("dracula"),
    ),
)

The variadic ...goldmark.Extender argument is the extension hook. The built-in extenders (GitHub-Flavoured Markdown, Footnote, Meta, Fences) always load. Goldmark appends the variadic arguments after them.

Bootstrap

ssr := piko.New(
    piko.WithMarkdownParser(parser),
)

This single line wires the parser into the collection service. The provider satisfies the parser port that piko.WithMarkdownParser expects, so a custom parser swaps in here without touching the rest of the configuration. The port contract lives in an internal package, so this option is the only entry point for a custom implementation. Piko does not export the port as a public type to implement against directly.

HTML conversion helper

The package also exports ToHTML(ctx, markdown, opts...) and ToHTMLBytes(ctx, markdown, opts...) for direct markdown-to-HTML conversion. These helpers run a separate Goldmark instance over the raw markdown. They do not consume the AST that Parse produces, and they enable only GFM and Footnote, not the Meta or Fences extensions.

The helpers strip raw HTML embedded in the markdown by default for security. Pass WithUnsafe() to render raw HTML, and only for fully trusted content.

html := markdown_provider_goldmark.ToHTML(ctx, "# Title\n\nBody text.")

See also

Sibling integrations:

  • Chroma, syntax highlighter. Wire it into Goldmark through goldmark-highlighting for colourised fenced code blocks.

Framework docs:

External: