Each is its own module with its own release line, so a program takes the model and the one format it reads โ never a stack of parsers it will not call.
The model itself โ an ordered list of blocks and a map[string]string of metadata, with no rendering, no parsing and no I/O at all. โ Blocks and inlines are closed interface sets: every concrete type carries an unexported marker method, so a converter can type-switch over them and the compiler knows when a case is missing. RawBlock and RawInline carry format-specific passthrough, which is what lets a round trip keep what the model has no word for. A cell holds blocks, not a line of text, because reST’s grid tables and HTML’s <td> both allow a paragraph, a list and a table inside one cell.
repository ยท pkg.go.dev
CommonMark and GFM, both directions. Parsing delegates to goldmark, the reference Go implementation โ tables, strikethrough, PHP-Markdown-Extra footnotes โ rather than hand-rolling a CommonMark parser. โ WithAutoHeadingID is deliberately off: auto ids would fabricate an anchor on every heading, and the writer would then stamp a {#id} the source never had. Only an anchor an author wrote is kept, which is what makes the round trip faithful rather than merely reversible.
repository ยท pkg.go.dev
reStructuredText, both directions, on go-docutils’s engine. โ It ships no reST parser of its own, because there is no gap to fill: docutils/rst is already a full, tested, pure-Go doctree producer, and a second one here would duplicate real work for no fidelity gain. That dependency doubles as this package’s own correctness proof.
repository ยท pkg.go.dev
A practical subset of LaTeX in, a compilable article out. โ This one does ship its own parser, and the reason is worth knowing: go-tex/engine is a typesetting engine whose tokenizer is internal โ it exposes a compile API, not a reusable parse tree. The preamble is mined for metadata, the document environment is read for content, and anything the model has no node for survives verbatim as RawInline/RawBlock with Format: "latex".
repository ยท pkg.go.dev
CSV, JSON, XML and plain text into a document, plus the richdata command that writes the result as Markdown. A table is the obvious shape for a CSV; what the package decides is everything else โ when a JSON object is a table and when it is a list, and when a log file is better left verbatim than parsed into something it is not.
repository ยท pkg.go.dev
FictionBook 2 (.fb2) in โ the one ebook format a reader can do with encoding/xml and nothing else: a single XML file, no ZIP, no package document, no spine, images base64 inside that same file. โ Section nesting is where a heading’s level comes from, since FB2 has no <h2>; a title broken over several <p> is one heading; an image becomes its bytes as a data URL, because #cover.jpg is a name nothing can resolve once the file is closed. One token representation rather than two typed fields, after encoding/xml silently filled only one of two ,any fields and every test came back empty with no error.
repository ยท pkg.go.dev
HTML and XHTML in, with the parse delegated to golang.org/x/net/html โ the piece the ebook formats were missing, since EPUB’s chapters are XHTML and an email’s body usually is too. โ What it drops is the interesting part: script, style, noscript and the head’s contents go completely, because a stylesheet is text in the tree like any other text and is the reason naive converters emit a page of CSS as the first paragraph. The test for it reads a real published page and fails if prefers-color-scheme reaches the document. โ Parsing XHTML with the HTML parser is also the safe choice: the HTML5 algorithm has no DTD, so an ebook cannot ask it to fetch a file or expand a billion laughs.
repository ยท pkg.go.dev
EPUB 2 and 3 in. An EPUB is three things in a trench coat โ a ZIP, a manifest and an order โ and none of them is the content. โ Nothing is found by its path: the container names the package document, which names its content, and the spine is the only thing that says what order to read it in; an alphabetical walk of the archive puts chapter 10 before chapter 2. An image becomes its bytes, and the same picture referred to fifty times is inflated once. Measured on eleven real books (7 480 to 377 683 words each) which are deliberately not in the repository: they are somebody’s library, and a fixture a test ships has to be one the repository may carry.
repository ยท pkg.go.dev
Kindle MOBI in โ three formats stacked on each other, and reading one is reading all three: a Palm database of records, a record 0 holding the PalmDOC and MOBI headers, and the book itself as ONE HTML document cut into 4096-byte pieces and each piece compressed on its own. โ The bytes at the end of a text record are not text and are not compressed โ indexing data, and the overlap of a multibyte character split across two records โ and feeding them to the decompressor does not fail: it produces plausible rubbish at the end of every record. โ Pictures are named by record number, two different ways, and kindle:embed:003C is base 32 and one-based: read as hexadecimal it would be wrong for every picture past the thirty-first and still look right for the first nine. Measured against Project Gutenberg’s own Pride and Prejudice with Gutenberg’s plain text of the same book as the judge: 125 816 words against 126 630, and 3 638 of 4 215 long sentences found verbatim. DRM, HUFF/CDIC and KF8 are refused by name, because none of those files is defective.
repository ยท pkg.go.dev
RFC 5322 messages and MIME in โ a .eml, or whatever an IMAP server hands back. โ Which part is the body is the whole job: an alternative is the same message twice and must be read once, a related is one message plus the pictures it names by Content-Id, a mixed is a sequence, and a signed is the message plus a signature that is not content. โ Nothing is fetched, ever: an HTML mail’s remote <img> is a tracking pixel as often as a picture, so only cid: parts that travelled inside the message are inlined โ there is no network code in the package and no way to ask for any.
repository ยท pkg.go.dev