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 ¶
- type Config
- type GitAttributes
- type Language
- type Policy
- type RefKind
- type RenderContext
- type RenderMode
- type Renderer
- func (r *Renderer) Classify(p string, content []byte, attrs GitAttributes) Language
- func (r *Renderer) Definitions(_ context.Context, _ []byte, _ string, _ string) []Tag
- func (r *Renderer) Highlight(code []byte, lang string) (template.HTML, error)
- func (r *Renderer) HighlightLines(code []byte, lang string) ([]template.HTML, error)
- func (r *Renderer) References(_ context.Context, _ []byte, _ string, _ string) []Tag
- func (r *Renderer) Render(ctx context.Context, src []byte, rc RenderContext) (template.HTML, error)
- func (r *Renderer) RenderComment(ctx context.Context, repo *RepoRef, src string) template.HTML
- func (r *Renderer) RenderFile(ctx context.Context, repo *RepoRef, ref, path, src string) template.HTML
- func (r *Renderer) ScanTags(_ context.Context, code []byte, grammar string) (SymbolIndex, bool)
- func (r *Renderer) Version() Versions
- type RepoRef
- type Symbol
- type SymbolIndex
- type Tag
- type TagKind
- type Versions
- type Viewer
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 512<<10; 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 ¶
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.
type RefKind ¶
type RefKind int
RefKind names the kind of reference the transform stage asks the caller to resolve.
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
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.
A render whose context carries no Resolve closure is a pure function of (src, rc, markupVersion), so it is served from the fragment cache; the cached value already passed the sanitizer, so a hit stays inside the trust boundary. With a Resolve closure present the output depends on caller state the cache key cannot see, so those renders always run the full pipeline.
func (*Renderer) RenderComment ¶
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 ¶
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.
type RepoRef ¶
RepoRef is the small repo identity the caller fills from its domain object. It keeps markup free of the domain package.
type Symbol ¶
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 ¶
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 ¶
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.