markup

package
v0.1.2 Latest Latest
Warning

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

Go to latest
Published: Jun 8, 2026 License: Apache-2.0 Imports: 28 Imported by: 0

Documentation

Overview

Package markup renders GitHub Flavored Markdown to sanitized, trusted HTML and highlights source code, for BOTH the web frontend and the REST text/html media type. It is a module-root package (a sibling of domain and presenter), never under fe/, because api/rest renders the same GFM through the same calls; it imports no fe/ package and no domain/store/git (the markup-boundary depguard rule, implementation/01 section 6).

Its RenderComment, RenderFile, Render, and Highlight methods are the only sanctioned producers of template.HTML from user or source content in the whole codebase. Every render path runs the bluemonday allowlist (sanitize.go) before returning, so injecting the result as template.HTML is safe by construction.

The package carries no clock, no RNG, and no map-iteration-order dependence in its output (anchor de-duplication uses a stable per-document counter), so its output is a pure function of (src, RenderContext, markupVersion) and the implementation/03 caches keyed on the version constants are sound. See implementation/10.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	BaseURL           string       // on-host base, for link/ref/anchor emission
	CamoSecret        []byte       // HMAC key for the off-host image proxy; empty disables proxying
	CamoBaseURL       string       // where the proxy is mounted (default {BaseURL}/camo)
	MaxHighlightBytes int          // default 5<<20; a larger blob is shown unhighlighted (logged)
	EmojiAssetBase    string       // asset path for custom :octocat:-style image emoji (unused in v1)
	Logger            *slog.Logger // optional; falls back to slog.Default
}

Config is the markup section of the app config (cfg.Markup, implementation/01).

type GitAttributes

type GitAttributes struct {
	Language      string // linguist-language=<name> override
	Vendored      bool   // linguist-vendored
	Generated     bool   // linguist-generated
	Documentation bool   // linguist-documentation
}

GitAttributes carries the .gitattributes signals that override detection, filled by the caller from the repo's attributes for the path.

type Language

type Language struct {
	Name    string
	Color   string
	Grammar string
}

Language is the classifier result: the display name, the Linguist color for the language bar, and the grammar id the highlighter keys on (the chroma lexer name in the pure-Go build).

type Policy

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

Policy wraps the bluemonday allowlist so the trust boundary is one named, testable artifact.

func NewPolicy

func NewPolicy() *Policy

NewPolicy builds the allowlist. It is deterministic and depends on no config, so the policy is identical on both surfaces. It is the GitHub-equivalent allowlist of implementation/10 section 5.

func (*Policy) Sanitize

func (pol *Policy) Sanitize(rendered []byte) []byte

Sanitize strips every tag, attribute, and URL scheme not on the allowlist; neutralizes javascript:/vbscript:; drops script/style/iframe/form and every on* handler and inline style. It is the only call that turns rendered HTML into sanitized HTML.

type RefKind

type RefKind int

RefKind names the kind of reference the transform stage asks the caller to resolve.

const (
	RefMention RefKind = iota // @user or @org/team
	RefIssue                  // #123, GH-123, owner/repo#123
	RefCommit                 // a bare commit SHA
)

RefKind values: a mention, an issue or PR reference, and a bare commit SHA.

type RenderContext

type RenderContext struct {
	Mode   RenderMode
	Repo   *RepoRef
	Ref    string // branch/tag/SHA, for File-mode relative-link rewriting
	Path   string // the file's in-repo path, for resolving relative links
	Viewer *Viewer

	// Resolve is the caller's hook the transform stage calls to decide whether a
	// @mention / #ref / SHA actually exists and is visible. It returns the link
	// target and whether to link at all. In ModePlain, or when Resolve is nil, no
	// mention/ref/SHA links, which is the safe no-repo default.
	Resolve func(ctx context.Context, kind RefKind, raw string) (target string, ok bool)
}

RenderContext controls reference resolution and link rewriting. It is a plain value the caller fills from its domain objects; markup never touches the domain. See implementation/10 section 2.

type RenderMode

type RenderMode int

RenderMode selects reference resolution and link rewriting.

const (
	ModeComment RenderMode = iota // issue/PR/commit comments, releases, descriptions
	ModeFile                      // a rendered README/Markdown file in the blob view
	ModeGist                      // a gist file (Spec 2004): refs off, gist-local links
	ModeWiki                      // a wiki page: non-notifying mentions
	ModePlain                     // /markdown/raw and any no-repo render: GFM + emoji only
)

RenderMode values: comment, file, gist, wiki, and plain, each selecting its own reference resolution and link rewriting.

type Renderer

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

Renderer holds the constructed goldmark instance, the bluemonday policy, the highlighter, and the classifier. It is built once and is safe for concurrent use: goldmark parsing is goroutine-safe and the policy is read-only after New.

func New

func New(cfg Config) *Renderer

New constructs the shared Renderer. It wires the sanitizer in front of every render path (a package test asserts this, since goldmark runs WithUnsafe), builds the highlighter and the classifier, and logs the highlighter backend once at startup so a deployment running a degraded backend is observable. It never fails on config alone; a missing CamoSecret only disables proxying.

func (*Renderer) Classify

func (r *Renderer) Classify(p string, content []byte, attrs GitAttributes) Language

Classify runs the precedence chain and returns the language. An unmatched path returns the zero Language, which the blob view renders monochrome.

func (*Renderer) Definitions

func (r *Renderer) Definitions(_ context.Context, _ []byte, _ string, _ string) []Tag

Definitions returns the definition tags for a symbol name in a blob. It is empty in the pure-Go build; the boolean from ScanTags is the signal callers gate on, and this mirrors it by returning nothing.

func (*Renderer) Highlight

func (r *Renderer) Highlight(code []byte, lang string) (template.HTML, error)

Highlight highlights code in the given language and returns its HTML: the source text HTML-escaped, with highlighted ranges wrapped in <span class="pl-..">. An unknown or unsupported language, or a blob over Config.MaxHighlightBytes, returns the escaped text with no spans (logged), never an error and never a failed page. The error return is reserved for a future backend that can fail internally; the current path never populates it.

func (*Renderer) HighlightLines

func (r *Renderer) HighlightLines(code []byte, lang string) ([]template.HTML, error)

HighlightLines returns the same content split per line, for the blob and diff table builders that pair each line with a gutter cell and a stable id.

func (*Renderer) References

func (r *Renderer) References(_ context.Context, _ []byte, _ string, _ string) []Tag

References returns the reference tags for a symbol name in a blob. Empty in the pure-Go build, for the same reason as Definitions.

func (*Renderer) Render

func (r *Renderer) Render(ctx context.Context, src []byte, rc RenderContext) (template.HTML, error)

Render is the general entry the /markdown and /markdown/raw API call with an explicit context (Plain when no repo is given). RenderComment and RenderFile are presets over it. It returns an error only for an internal failure; a malformed document still renders, since CommonMark is total.

func (*Renderer) RenderComment

func (r *Renderer) RenderComment(ctx context.Context, repo *RepoRef, src string) template.HTML

RenderComment renders a comment body, release note, or repo description: ModeComment, full GitHub-extension processing, notifying mentions, relative links against the repo default branch. This is the method the view layer calls for BodyHTML and the REST text/html media type calls for a comment.

func (*Renderer) RenderFile

func (r *Renderer) RenderFile(ctx context.Context, repo *RepoRef, ref, path, src string) template.HTML

RenderFile renders a README/Markdown file in the blob or repo-home view: ModeFile, non-notifying mentions, relative links/images rewritten against the file's ref and path. ref and path place the rewriting.

func (*Renderer) ScanTags

func (r *Renderer) ScanTags(_ context.Context, code []byte, grammar string) (SymbolIndex, bool)

ScanTags parses code in the given grammar and returns its symbol index. In the pure-Go build it returns ok=false: there is no parse tree to derive tags from, so the caller renders the blob without navigation rather than with wrong links. The Tree-sitter build will return a populated index and ok=true.

func (*Renderer) Version

func (r *Renderer) Version() Versions

Version returns the renderer's three version integers.

type RepoRef

type RepoRef struct {
	Owner string
	Name  string
	ID    int64
}

RepoRef is the small repo identity the caller fills from its domain object. It keeps markup free of the domain package.

type Symbol

type Symbol struct {
	Name       string
	Definition Tag
	References []Tag
}

Symbol is a named definition with the set of places it is referenced, the unit a jump-to-definition / find-references panel is built from.

type SymbolIndex

type SymbolIndex struct {
	Symbols map[string]Symbol
	Tags    []Tag
}

SymbolIndex is the per-blob result of tag scanning: the definitions keyed by name and the flat occurrence list. The zero value is a valid empty index.

type Tag

type Tag struct {
	Name string
	Kind TagKind
	Line int
	Col  int
}

Tag is one symbol occurrence located in a blob: its name, what kind of occurrence it is, and the 1-based line and column where it starts.

type TagKind

type TagKind int

TagKind classifies a symbol occurrence.

const (
	TagDefinition TagKind = iota
	TagReference
)

TagKind values: TagDefinition is the site where a symbol is defined, TagReference is a use of it.

type Versions

type Versions struct{ Markup, Highlighter, Tags int }

Versions exposes the three constants for cache keys and for an admin/debug header, so a deployed instance's renderer version is observable.

type Viewer

type Viewer struct {
	ID    int64
	Login string
}

Viewer is the small viewer identity the caller fills from its session. It is used only to let the caller's Resolve closure visibility-gate a reference.

Jump to

Keyboard shortcuts

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