config

package
v0.8.2 Latest Latest
Warning

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

Go to latest
Published: Jul 24, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

bookjson.go provides GitBook book.json compatibility for mdPress. It parses a GitBook-style book.json file and converts it to a BookConfig.

Package config loads and validates mdpress configuration. It reads book metadata, chapter definitions, style settings, and output options from book.yaml.

discover.go implements zero-config project discovery. When neither book.yaml nor SUMMARY.md exists, mdpress scans .md files, sorts them, and derives chapter metadata automatically.

layout.go resolves the page geometry a paginated build uses.

Page size and margins can come from three places: the theme file, book.yaml's `style` block, and book.yaml's `output.margin_*` keys. Only the last two ever reached a renderer. DefaultConfig pre-fills style.page_size ("A4") and style.margin (25/25/20/20), and every consumer reads those config fields, so a themes/<name>.yaml declaring `page_size: A5` and wider `margins:` — values theme validation *requires* and `mdpress themes show` advertises — changed nothing at all in the finished PDF.

natural_sort.go orders file names the way their author numbered them.

Plain lexical order puts "10-deploy.md" and "11-scale.md" ahead of "2-install.md", which silently reorders a book whose chapters are numbered past nine — and neither build nor validate had any way to notice.

set_keys.go records which settings the project actually wrote down.

Almost every setting mdpress resolves from more than one source has to answer the question "did the user configure this?", and comparing the loaded value against DefaultConfig() cannot answer it: Load unmarshals *over* DefaultConfig, so a field holding the default value is indistinguishable from a field the user typed by hand. That confusion has shipped repeatedly — a book.json pinned to `"version": "1.0.0"` was replaced by a git tag, a theme's page_size never reached any renderer because style.page_size was pre-filled with "A4". So key presence is recorded while parsing, and every "is this configured?" test asks IsSet instead of guessing from the value.

summary.go parses chapter structure from SUMMARY.md. SUMMARY.md uses Markdown link lists to define chapter order in a GitBook-compatible format.

Format example:

# Summary

* [Preface](preface.md)
* [Chapter 1](chapter01/README.md)
  * [Section 1.1](chapter01/section01.md)
* [Chapter 2](chapter02/README.md)

unknown_keys.go reports book.yaml keys that mdpress does not recognize.

The loader is deliberately non-strict — an unknown key must not break a build that used to work, and forward compatibility matters for a config file people copy between versions. But silently discarding a key is the worst possible outcome for the user: they edit book.yaml, rebuild, see no change, and have nothing to debug with. So unknown keys are surfaced as warnings, with a suggestion when a known sibling is close enough to be the intent.

Index

Constants

View Source
const DefaultBookTitle = "Untitled Book"

DefaultBookTitle is the placeholder used when book.title is unset. It is exported so callers can tell "the user named their book" from "nothing took effect" — reporting the placeholder as a valid title hid typo'd config keys.

Variables

This section is empty.

Functions

func IsValidPageSize added in v0.7.0

func IsValidPageSize(s string) bool

IsValidPageSize reports whether s is a recognized page size name (case-insensitive).

func NaturalCompare added in v0.8.0

func NaturalCompare(a, b string) int

NaturalCompare compares a and b treating runs of digits as numbers, so "2-install" sorts before "10-deploy". It returns a negative number when a sorts first, zero when the two are equivalent, and a positive number otherwise, matching the contract of cmp.Compare.

func NaturalLess added in v0.8.0

func NaturalLess(a, b string) bool

NaturalLess reports whether a sorts before b in natural order.

func TitleFromDirName added in v0.8.0

func TitleFromDirName(dir string) string

TitleFromDirName turns a project directory path into a readable book title, e.g. "/src/my-docs" → "My docs". It is exported so that `mdpress init` picks the same title as zero-config discovery for the same directory — the two used to disagree, and so did the artifact names derived from them.

func ValidationErrors added in v0.8.0

func ValidationErrors(err error) []error

ValidationErrors flattens an error returned by BookConfig.Validate (or a wrapper around one) into the individual problems it reports, so a caller can render one line per problem instead of a single blob of joined text. A nil error yields nil; an error that is not a join yields a one-element slice.

Types

type BookConfig

type BookConfig struct {
	Book     BookMeta       `yaml:"book"`
	Chapters []ChapterDef   `yaml:"chapters"`
	Style    StyleConfig    `yaml:"style"`
	Output   OutputConfig   `yaml:"output"`
	Markdown MarkdownConfig `yaml:"markdown"`
	// Plugins lists the plugins to run during the build, in declaration order.
	Plugins []PluginConfig `yaml:"plugins"`
	// Variables are user-defined template variables, usable in Markdown as
	// {{ key }} alongside the built-in book.*/style.*/output.* values.
	Variables map[string]string `yaml:"variables"`

	// These fields are auto-detected by Load instead of being set directly in YAML.
	GlossaryFile string `yaml:"-"` // Path to GLOSSARY.md, if present.
	LangsFile    string `yaml:"-"` // Path to LANGS.md, if present.
	// contains filtered or unexported fields
}

BookConfig is the top-level configuration for a book.

func DefaultConfig

func DefaultConfig() *BookConfig

DefaultConfig returns a config populated with reasonable defaults.

func Discover

func Discover(ctx context.Context, dir string) (*BookConfig, error)

Discover auto-discovers project configuration in a directory. Priority: book.yaml > book.json (GitBook compat) > SUMMARY.md > Markdown file scanning. The context is used for potentially long-running operations like git commands.

func Load

func Load(path string) (*BookConfig, error)

Load reads a config file from disk. If chapters are empty, it attempts to load them from SUMMARY.md in the same directory. It also auto-detects GLOSSARY.md and LANGS.md.

func LoadBookJSON added in v0.3.1

func LoadBookJSON(ctx context.Context, path string) (*BookConfig, error)

LoadBookJSON reads a GitBook book.json file and returns an equivalent BookConfig.

Metadata fields (title, author, description, language, plugins) are loaded from book.json. Chapter definitions are NOT loaded here; instead, Discover() handles chapters via SUMMARY.md or auto-discovery, which allows proper priority orchestration of configuration sources. The context is used for potentially long-running operations like git commands.

func (*BookConfig) AllowRawHTML added in v0.8.0

func (c *BookConfig) AllowRawHTML() bool

AllowRawHTML reports whether raw HTML embedded in Markdown should be rendered as HTML rather than escaped.

mdpress treats Markdown sources as trusted input — they come from the same repository as book.yaml — so this defaults to true and raw HTML passes through unfiltered, including <script> and <iframe>. A project that renders Markdown it did not write (community contributions, user submissions) should set `markdown.allow_html: false`.

func (*BookConfig) ApplyThemeLayout added in v0.8.2

func (c *BookConfig) ApplyThemeLayout(pageSize string, margins MarginConfig)

ApplyThemeLayout fills in page geometry the project did not configure, using the theme's own values. book.yaml's `style` block still wins wherever it actually said something; ApplyTypography does the same for fonts.

Margins are taken as a block: all-zero margins are what a theme file that omits the `margins:` key yields, and theme.ToCSS already reads that as "unset" rather than as an edge-to-edge page. Individual edges are still honored one by one, so `style: {margin: {top: 5}}` keeps the theme's other three sides.

func (*BookConfig) BaseDir

func (c *BookConfig) BaseDir() string

BaseDir returns the directory containing the config file.

func (*BookConfig) IsSet added in v0.8.2

func (c *BookConfig) IsSet(path string) bool

IsSet reports whether path — a dotted YAML location such as "book.version" or "style.margin.top" — was present in the configuration the project supplied. It is false for anything that came from DefaultConfig, from zero-config discovery, or from any other inference, which is exactly the distinction a value comparison cannot make.

func (*BookConfig) ResolvePath

func (c *BookConfig) ResolvePath(p string) string

ResolvePath resolves a path relative to the config directory.

Security: This function does NOT verify that the result is contained within the project directory. It is the caller's responsibility to ensure the input path has been validated (e.g. via utils.SafeJoin or BookConfig.Validate) before passing it here. Absolute paths are returned unchanged, so an attacker-controlled absolute path could escape the project root.

func (*BookConfig) SetBaseDir

func (c *BookConfig) SetBaseDir(dir string)

SetBaseDir overrides the base directory used to resolve relative paths. It is primarily useful for tests and for constructing configs in memory.

func (*BookConfig) Validate

func (c *BookConfig) Validate() error

Validate checks the configuration for completeness and validity.

It reports every independent problem it finds rather than stopping at the first one: a book.yaml with five mistakes used to take five edit-and-rerun cycles to clean up. The result is an errors.Join value, so callers that want to render one line per problem can unwrap it with ValidationErrors.

type BookMeta

type BookMeta struct {
	Title       string    `yaml:"title"`
	Subtitle    string    `yaml:"subtitle"`
	Author      string    `yaml:"author"`
	Version     string    `yaml:"version"`
	Language    string    `yaml:"language"`
	Description string    `yaml:"description"`
	Cover       CoverMeta `yaml:"cover"`
	// Favicon is the site icon: a project-relative image path, or an absolute
	// URL. Empty keeps mdpress's built-in book emoji.
	Favicon string `yaml:"favicon"`
	// project-relative image path, or an absolute URL. Empty shows no logo.
	Logo string `yaml:"logo"`
	// Copyright is a short notice rendered in each page's footer, e.g.
	// "© 2026 Acme Inc.". Empty renders no notice.
	Copyright string `yaml:"copyright"`
}

BookMeta contains book metadata.

type ChapterDef

type ChapterDef struct {
	Title string `yaml:"title"`
	File  string `yaml:"file"`
	// Section is an optional group label rendered above this chapter in the
	// site sidebar, starting a new group. SUMMARY.md "## Heading" lines set it
	// on the chapter that follows them; book.yaml can set it directly. It is
	// carried on a real chapter rather than modeled as a file-less entry, so
	// nothing downstream has to cope with a chapter that has no content.
	Section  string       `yaml:"section"`
	Sections []ChapterDef `yaml:"sections"`
}

ChapterDef defines a chapter and its nested sections.

func FlattenChapters

func FlattenChapters(chapters []ChapterDef) []ChapterDef

FlattenChapters expands nested chapter definitions into a flat list. This is the canonical implementation; callers should use this instead of maintaining their own flattening logic.

func ParseSummary

func ParseSummary(path string) ([]ChapterDef, error)

ParseSummary parses chapter definitions from SUMMARY.md. Nesting is expressed with indentation: two spaces or one tab per level.

type CoverMeta

type CoverMeta struct {
	Image      string `yaml:"image"`
	Background string `yaml:"background"` // Background color, for example "#1a1a2e".
}

CoverMeta stores cover configuration.

type DiscoverError

type DiscoverError struct {
	Dir string
	Msg string
}

DiscoverError describes auto-discovery failures.

func (*DiscoverError) Error

func (e *DiscoverError) Error() string

type HeaderFooterStyle

type HeaderFooterStyle struct {
	Left   string `yaml:"left"`
	Center string `yaml:"center"`
	Right  string `yaml:"right"`
}

HeaderFooterStyle stores header and footer text templates.

type MarginConfig

type MarginConfig struct {
	Top    float64 `yaml:"top"`
	Bottom float64 `yaml:"bottom"`
	Left   float64 `yaml:"left"`
	Right  float64 `yaml:"right"`
}

MarginConfig stores page margins in millimeters.

type MarkdownConfig added in v0.8.0

type MarkdownConfig struct {
	// AllowHTML controls whether raw HTML written in Markdown reaches the
	// output. A nil pointer means "not configured" and keeps the default.
	AllowHTML *bool `yaml:"allow_html"`
}

MarkdownConfig controls how Markdown sources are parsed.

type OutputConfig

type OutputConfig struct {
	Filename          string   `yaml:"filename"`
	TOC               bool     `yaml:"toc"`
	TOCMaxDepth       int      `yaml:"toc_max_depth"` // Maximum heading level to include in TOC (1-6, default 2). Level 1 = h1 only, 2 = h1+h2, etc.
	Cover             bool     `yaml:"cover"`
	Header            bool     `yaml:"header"`
	Footer            bool     `yaml:"footer"`
	Formats           []string `yaml:"formats"`            // Output formats: pdf, html, epub, site (default ["pdf"]).
	PDFTimeout        int      `yaml:"pdf_timeout"`        // PDF generation timeout in seconds (default 120).
	Watermark         string   `yaml:"watermark"`          // Watermark text (e.g., "DRAFT", "CONFIDENTIAL")
	WatermarkOpacity  float64  `yaml:"watermark_opacity"`  // Opacity 0.0-1.0 (default 0.1)
	MarginTop         string   `yaml:"margin_top"`         // e.g., "20mm"; unset means style.margin.top
	MarginBottom      string   `yaml:"margin_bottom"`      // e.g., "20mm"; unset means style.margin.bottom
	MarginLeft        string   `yaml:"margin_left"`        // e.g., "25mm"; unset means style.margin.left
	MarginRight       string   `yaml:"margin_right"`       // e.g., "25mm"; unset means style.margin.right
	GenerateBookmarks bool     `yaml:"generate_bookmarks"` // Generate PDF bookmarks from headings (default true)
	SiteURL           string   `yaml:"site_url"`           // Public base URL of the deployed site (e.g. https://user.github.io/repo); enables sitemap.xml
	EditBase          string   `yaml:"edit_base"`          // Base URL for "edit this page" links (e.g. https://github.com/user/repo/edit/main/)
	TaggedPDF         *bool    `yaml:"tagged_pdf"`         // Generate accessible tagged PDF (default true; false produces smaller files)
	// FooterHTML replaces the site's default "Built with mdPress" footer line.
	// A nil pointer means "not configured" and keeps the default; an explicit
	// empty string removes the line. It is a pointer for exactly that reason —
	// a plain string cannot tell "unset" from "the user wants no footer".
	// Its value is emitted as raw HTML, on the same trust footing as raw HTML
	// in the Markdown sources (see BookConfig.AllowRawHTML).
	FooterHTML *string `yaml:"footer_html"`
	// ShowThemeBadge renders the theme name as a badge in the site sidebar.
	// Off by default: it is mdpress advertising itself on someone else's
	// published site, and removing it used to require a CSS hack.
	ShowThemeBadge bool `yaml:"show_theme_badge"`
}

OutputConfig stores output-related settings.

type PluginConfig added in v0.3.0

type PluginConfig struct {
	// Name is the unique plugin identifier (lowercase, hyphen-separated).
	Name string `yaml:"name"`
	// Path is the path to the plugin executable, relative to book.yaml.
	Path string `yaml:"path"`
	// Config contains arbitrary key-value pairs passed to the plugin.
	Config map[string]any `yaml:"config"`
}

PluginConfig describes a single plugin entry in book.yaml.

Example:

plugins:
  - name: word-count
    path: ./plugins/word-count
    config:
      warn_threshold: 500

type ReadmeMetadata added in v0.3.1

type ReadmeMetadata struct {
	Title    string // Book title (may differ from H1 heading).
	Version  string // e.g. "1.6.5"
	Author   string // Detected author name or GitHub username.
	Language string // e.g. "zh-CN", "en-US"
}

ReadmeMetadata holds metadata extracted from a project README.md.

func ExtractReadmeMetadata added in v0.3.1

func ExtractReadmeMetadata(ctx context.Context, path string) ReadmeMetadata

ExtractReadmeMetadata reads a README.md and extracts book metadata. It tries to find a meaningful title (beyond just the H1), version, language, and author. Exported so that cmd/init_cmd.go can also use it. The context is used for potentially long-running operations like git commands.

type StyleConfig

type StyleConfig struct {
	Theme      string            `yaml:"theme"`
	PageSize   string            `yaml:"page_size"`
	FontFamily string            `yaml:"font_family"`
	FontSize   string            `yaml:"font_size"`
	CodeTheme  string            `yaml:"code_theme"`
	LineHeight float64           `yaml:"line_height"`
	Margin     MarginConfig      `yaml:"margin"`
	Header     HeaderFooterStyle `yaml:"header"`
	Footer     HeaderFooterStyle `yaml:"footer"`
	CustomCSS  string            `yaml:"custom_css"`
}

StyleConfig stores style-related settings.

type UnknownKey added in v0.8.0

type UnknownKey struct {
	// Path is the dotted location in the document, e.g. "style.them".
	Path string
	// Suggestion is the closest known sibling key, or "" if none is close.
	Suggestion string
}

UnknownKey is a config key with no corresponding field.

func FindUnknownKeys added in v0.8.0

func FindUnknownKeys(data []byte) []UnknownKey

FindUnknownKeys parses data as a generic document and walks it against the BookConfig type, collecting keys with no matching field.

func (UnknownKey) Hint added in v0.8.0

func (u UnknownKey) Hint() string

Hint renders the "did you mean" text for a warning, or a generic note.

Jump to

Keyboard shortcuts

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