Skip to content

Overview

go-richdoc

One rich-document model, and the converters that read and write it — Markdown, LaTeX, reStructuredText, HTML, EPUB, Kindle MOBI, FictionBook, email, CSV, JSON, XML and plain text.

Part of the Documents, typesetting & fonts family of the pure-Go ecosystem — 10 modules, all CGO_ENABLED=0.

What is here

This site is the organisation’s reference index: what each module is, and where its API documentation lives. The API itself is generated from the source and served by pkg.go.dev, which is always current with the released tags — duplicating it here would only create a second copy to go stale.

  • Modules — every module in go-richdoc, with its source and its reference.

One thing to know before converting untrusted input

A converter turns one format into another, so the question is whether CONTENT CAN BECOME MARKUP on the way out. It could, once: a Markdown heading of # <b>.. include:: /etc/passwd</b> became a reST directive, because reST tries explicit markup before it tries a title — and a docutils parse with a source path then reads that file. Fixed in rst v0.3.0, with a probe over every position a document can hold text to say it was the only one (injectprobe: 14 pairs where text became markup, 0 after; nothing at all in markdown or latex).

What no converter here protects you from, because the reference does not either: a URI scheme. javascript:alert(1) in a link survives every hop, and docutils writes the same href. An allow-list belongs in whatever renders the model. Each repository’s README has a Security section with its own audit.

The model, in one paragraph

richdoc is a typed tree: a Document of Blocks and Inlines, both CLOSED interface sets, so a converter can type-switch over them exhaustively. Each converter maps one format onto that tree in both directions. Where a format has something the model does not, the converter says so in its own README with the population it measured — that is how the model grows: Classes on the nodes that carry them (v0.4.0), Cell.Blocks and Table.Caption (v0.5.0), each added because a corpus showed what was being dropped, and each additive so no existing consumer breaks.

What every module here is held to

  • CGO_ENABLED=0: no cgo, and no shelling out to a command-line tool in place of a library.
  • Built for ten targets — linux/{amd64,arm64,riscv64,loong64,ppc64le,s390x}, darwin/{amd64,arm64}, windows/amd64 and js/wasm — and tested on amd64, with the race detector.

⛔ Built is not tested, and this page used to say both at once

It read “built and tested on amd64, arm64, riscv64, loong64, ppc64le and s390x”. Cross-compiling proves a program compiles; it says nothing about what it does when a byte order or a word size differs. These modules are a tree and a great deal of string handling, which is a different risk from a format whose integers come off a disk — and where that is the risk, the lane exists: go-ooxml runs its suite under qemu on five more architectures, big-endian s390x included, because an OPC package is a ZIP full of little-endian integers.

  • 100% statement coverage as a CI gate, error branches included — with one stated exception: rst enforces a 94% floor instead. It walks a doctree whose exact shape it does not control (go-docutils/docutils is a separate, independently evolving engine), so its ok-checked type assertions and its default: case for an unknown doctree tag are a safety net for a FUTURE tag rather than dead code. The reason is in that repository’s own workflow, beside the number.
  • BSD-3-Clause.

The standard is described in full on the ecosystem map.