export

package
v0.16.2 Latest Latest
Warning

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

Go to latest
Published: Sep 14, 2026 License: Apache-2.0 Imports: 29 Imported by: 0

Documentation

Overview

Package export turns a KB markdown note into a downloadable document — HTML, DOCX, or PDF. It is the sanctioned reverse of internal/convert (which is one-directional, into markdown), and is kept in its own package precisely so that convert stays into-markdown-only.

Like convert, this is a pure function of its input for the always-available formats: HTML and DOCX need no host tools and no network, which is what makes them testable against golden fixtures and identical across hosts. PDF is the one best-effort format — it shells out to whichever headless renderer happens to be on PATH — mirroring how convert prefers an external pdftotext when one is installed but never requires it.

The package renders markdown as-is: splitting frontmatter off the note, or choosing a filename, is the caller's job (the KB export handler). Callers pass the note body they want in the document.

Index

Constants

This section is empty.

Variables

View Source
var ErrNoPDFEngine = errors.New("export: no PDF engine available")

ErrNoPDFEngine is returned by ToPDF when no supported headless renderer is on PATH. It is a property of the HOST (nothing is installed), never a fault of the input, so the handler can turn it into a "install one of these tools for PDF export" message rather than a generic 500. Callers use errors.Is against it.

Functions

func SplitAltWidth added in v0.15.0

func SplitAltWidth(alt string) (string, int)

SplitAltWidth separates an image's real alt text from the pixel width the editor stores alongside it in Obsidian's `![alt|420](src)` form.

It must agree exactly with the editor's TypeScript splitAltWidth (web/ui/src/pages/kb/imageResize.ts), which is why the rule is stated the same way in both: split on the LAST pipe, and only when the tail is a bare integer, so an alt that genuinely contains a pipe survives.

Returns a width of 0 when there is none. 0 rather than a pointer because "no width" and "zero width" are the same instruction here — render at the image's natural size — and a pointer would invite a nil check at every call site to express nothing extra.

func ToDOCX

func ToDOCX(md []byte, opts Options) ([]byte, error)

ToDOCX renders a markdown note into a minimal OOXML (.docx) package, built pure-Go with archive/zip + encoding/xml so it is always available with no host tools. It mirrors how internal/convert READS docx (a zip of XML parts); this is the write side.

The package is deliberately four parts — [Content_Types].xml, _rels/.rels, word/_rels/document.xml.rels, and word/document.xml. That means no numbering.xml and no styles.xml: lists render with literal markers ("• "/"1. ") rather than real <w:numPr> numbering (which would require numbering.xml), and headings use Word's built-in "HeadingN" styles by name (Word supplies them even without a styles part). Hyperlinks are the one feature needing a rels entry, and document.xml.rels is one of the four parts — so it stays coherent.

Supported block set: headings, paragraphs, bold/italic/inline-code/strike runs, bullet & numbered lists (incl. nesting), blockquotes, code blocks (monospace), tables, horizontal rules, and external hyperlinks. Anything unrecognized degrades to a plain paragraph of its text rather than failing.

func ToHTML

func ToHTML(md []byte, opts Options) ([]byte, error)

ToHTML renders a markdown note into a self-contained HTML document with readable inlined CSS. Wikilinks are flattened to their display text first; raw HTML in the note is dropped (goldmark's safe default), so the output can never carry an injected <script>. External links are preserved. This HTML is also the source ToPDF hands to a headless renderer.

func ToPDF

func ToPDF(md []byte, opts Options) ([]byte, error)

ToPDF renders the note to HTML (the same document ToHTML produces) and converts it with the first headless renderer available. With none installed it returns ErrNoPDFEngine so the caller can prompt the operator to install one, rather than failing opaquely.

The HTML is written to a temp file; the engine reads it and writes the PDF to a sibling temp file; both are cleaned up. The subprocess is bounded by pdfTimeout.

Types

type Attachment added in v0.15.0

type Attachment struct {
	Name string // the link's visible text, or the file name when it has none
	Path string // the vault-relative path, shown so a reader can ask for it
}

Attachment is one non-image file a note links to.

type Formats

type Formats struct {
	HTML bool `json:"html"`
	DOCX bool `json:"docx"`
	PDF  bool `json:"pdf"`
}

Formats reports which export formats are usable right now. HTML and DOCX are always true (pure-Go, no host deps); PDF is true only when a headless renderer is on PATH. The UI uses this to grey out PDF when it can't be produced.

func AvailableFormats

func AvailableFormats() Formats

AvailableFormats reports the formats this host can currently produce.

type Options

type Options struct {
	// Title is used for the HTML document's <title> and the DOCX document
	// title. When empty a neutral default ("Note") is used so the output is
	// never headless.
	Title string

	// Attachments are the non-image files the note links to, listed at the end
	// of the exported document.
	//
	// They are LISTED rather than embedded, and that is a limitation of the
	// export path rather than an oversight. Images are inlined as data: URIs by
	// the caller, but goldmark deliberately blanks a data: URI in an <a href> —
	// a security property this path keeps — so a linked PDF cannot be carried
	// the same way. Without the list, a downloaded document has a relative link
	// that resolves to nothing and gives the reader no clue what it pointed at.
	Attachments []Attachment
}

Options carries rendering hints. Every field is optional; a zero Options produces a valid document with generic defaults.

Jump to

Keyboard shortcuts

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