Documentation
¶
Overview ¶
Package build is the build pipeline: it walks a project's docs templates, resolves their directives, wraps each page in its chrome, and writes a whole static site under the configured output directory.
Build is the entry point. It loops locales outside versions, builds each combination -- the current version from the working tree, every superseded one from a git tag extracted into the version cache -- and then writes the files that belong to the site rather than to a page: the stylesheet, the social cards, the sitemaps, llms.txt, the Atom feed, the favicon, robots.txt, the redirect stubs, the search index and the compressed companions.
BuildSingle is one locale-and-version pass, and the only thing in the package that a caller can run without producing a site: it returns everything it built instead of writing it, which is what makes the in-memory render path possible.
Every write and every subprocess is declared ¶
Nothing here touches os/exec or the filesystem's mutating calls directly. Each function that writes or spawns takes an effects.Handle and goes through it, so a --dry-run records the whole build instead of performing it. Reads are not effects and use the standard library.
Ordering is sorted, not walk order ¶
The Python this replaces carried insertion-ordered dicts of pages, in the arbitrary order os.walk yielded them. A Go map has no order, so every page collection here is a slice sorted by the page's docs-relative path, and the three decisions that read the order -- which nav group title wins when two pages in one directory declare different ones, how two groups whose titles sort equal are ordered, and which page is converted first -- are therefore decided by path rather than by directory listing.
Index ¶
- Constants
- func AddImageDimensions(htmlText, docsDir, pageRelPath string) string
- func Build(opts Options, h *effects.Handle) (map[string]bool, error)
- func BuildPostsOnly(dirPath string, cfg config.Config, outputDir, docsDirName, docsDir string, ...) (map[string]bool, error)
- func CheckPostSlugUniqueness(claims []SlugClaim) error
- func CheckReservedAuthoredPages(docsDir, baseDir string) error
- func CheckReservedPagePaths(mdPaths map[string]bool) error
- func CleanupInjectedPosts(injectedFiles []string, docsDir string, h *effects.Handle) error
- func CompressOutput(outputDir string, h *effects.Handle) (count int, err error)
- func DefaultLocaleOf(cfg config.Config) string
- func ExtractCriticalCSS(fullCSS string) (critical, full string)
- func ExtractVersionContent(version string, config map[string]any, baseDir string, h *effects.Handle) (string, error)
- func GenerateAtomFeed(opts FeedOptions, h *effects.Handle) (string, error)
- func GenerateAuxiliaryFiles(opts AuxiliaryOptions, h *effects.Handle) (map[string]bool, error)
- func GenerateFaviconSVG(projectName, accentColor string) string
- func GenerateHeaders(outputDir string, h *effects.Handle) (string, error)
- func GenerateLLMSFullTxt(projectName string, markdownFiles []page.SourceFile) string
- func GenerateLLMSTxt(projectName string, markdownFiles []page.SourceFile, ...) (string, error)
- func GenerateOGPNGBasic(accentColor string) ([]byte, error)
- func GeneratePerLocaleSitemaps(outputDir string, localeCodes []string, ...) ([]string, error)
- func GenerateRobotsTxt(outputDir string, urlBuilder urls.URLBuilder, hasSitemapIndex bool, ...) (string, error)
- func GenerateSitemap(htmlPaths []string, urlBuilder urls.URLBuilder, ...) string
- func GenerateSitemapIndex(outputDir string, localeCodes []string, urlBuilder urls.URLBuilder, ...) (string, error)
- func InjectPostsIntoDocs(dirPath string, cfg config.Config, docsDir string, includeDrafts bool, ...) ([]string, error)
- func IsSiteLevelPage(mdPath string) bool
- func MakeURLBuilder(config map[string]any) urls.URLBuilder
- func MinifyCSS(cssText string) string
- func MinifyHTML(htmlText string) string
- func PostDocsPayloads(publishedPosts []posts.Post) (map[string]string, error)
- func PruneUnreferencedPagefindWidget(siteDir string, h *effects.Handle) ([]string, error)
- func RenderPostListing(publishedPosts []posts.Post) (string, error)
- func ResolveLocaleDocsDir(dirPath, docsDirName, localeCode string, locales []map[string]any) (string, error)
- func RunPagefind(outputDir string, h *effects.Handle) error
- func SiblingsBlockRange(pageHTML string) (int, int, bool)
- func VersionedHTMLPaths(buildDir, docsDirName, localeCode string, locales []map[string]any, ...) (map[string]bool, error)
- func WithRefreshedSiblings(pageHTML, siteHop string, siblings []SiblingProject) string
- type AuxiliaryOptions
- type BuildResult
- type FeedEntry
- type FeedOptions
- type Options
- type Partition
- type SiblingProject
- type SingleOptions
- type SlugClaim
Constants ¶
const ( SiblingsBlockStart = `<section class="sibling-projects" ` + `data-pagefind-ignore aria-labelledby="sibling-projects-heading">` SiblingsBlockEnd = "</section>" )
SiblingsBlockStart and SiblingsBlockEnd delimit the block on a built page.
They are markers rather than an internal detail of the rendering because the block is not only written: the assembly regenerates it in place on pages earlier deploys wrote (see WithRefreshedSiblings), and finding it is what that needs. The section element itself carries the markers -- an element already on every page the block was ever written on, back to the first one -- so a page published under any earlier toolchain is found by the same rule as a page published today.
The start is the whole opening tag, which one page carries at most one of. The end is the closing tag of that element; the rendering below nests no section inside the block, so the first one after the opening tag closes it.
const CriticalCSSMarker = "/* --- NON-CRITICAL --- */"
CriticalCSSMarker separates a theme stylesheet's critical part -- the styles the first paint needs -- from the rest, which a page loads asynchronously.
The themes package states the same marker for its own split of the embedded stylesheets, and the two have to be equal: the sheet this function splits is the one that package composed.
const SiblingsHeading = "More tools from this site"
SiblingsHeading heads the section every assembled page carries at the end of its body.
Variables ¶
This section is empty.
Functions ¶
func AddImageDimensions ¶
AddImageDimensions adds width and height attributes to every img element whose source file exists on disk.
Each src is resolved relative to the page's own directory inside docsDir; an external URL is left alone, and so is a file whose format none of the readers recognizes. The attributes are inserted before the tag's first ">", which is where the Python inserted them and therefore what every rendered page states.
func Build ¶
Build builds a project's documentation site and returns the paths it wrote.
Locales are the outer loop and versions the inner one. Each combination is built from either the working tree (the current version) or a git tag extracted into the version cache (a superseded one). The current version of every page is emitted at the stable address and every older version under "v/<version>/"; the pages marked "versioned: false" are emitted once at the version-free mount, and the site-level pages (the posts and their listing) once with no mount at all.
After the pages come the files that belong to the site: the theme stylesheet and its assets, the social cards, the sitemaps, llms.txt, the Atom feed, the 404 page, the favicon, robots.txt, the redirect stubs, the Pagefind index and the compressed companions.
func BuildPostsOnly ¶
func BuildPostsOnly( dirPath string, cfg config.Config, outputDir, docsDirName, docsDir string, includeDrafts bool, siblings []SiblingProject, siteName string, h *effects.Handle, ) (map[string]bool, error)
BuildPostsOnly builds only the post pages, skipping the versioned docs and every site-level file.
It injects the posts into the docs tree, runs them through BuildSingle with a page filter and no mount, writes the HTML, cleans up, and writes a post-manifest. No sitemap, feed, search index or stylesheet is produced.
The mount is empty here and the post pages are site-level in the full build too, so a post is at "blog/<slug>/" either way -- the two builds cannot disagree about where a post lives. The arguments handed to BuildSingle are the ones the full build's site-level pass uses, for the same reason: the assembly rebuilds posts alone when only a post changed and grafts the result beside the full build's output, so any disagreement would make the last build to run decide what the site serves.
It returns the paths written.
func CheckPostSlugUniqueness ¶
CheckPostSlugUniqueness refuses two posts claiming the same site-level address.
Posts are emitted at "blog/<slug>/" with no project segment, so on a site assembled from several projects the slug namespace is shared. A repeat would silently overwrite one post with another, so it is an error naming both sources.
Each claim pairs a slug with whatever produced the post -- a project slug, a file path.
func CheckReservedAuthoredPages ¶
CheckReservedAuthoredPages refuses an authored page sitting where the build writes its own files.
CheckReservedPagePaths runs on the partitioned page sets, and the site-level partition holds the pages injection just wrote, so it can never see an AUTHORED blog.md: injection had already overwritten it, and cleanup deleted it afterwards. This reads the tree itself, before anything writes into it, and refuses the file.
docsDir is a docs tree (a locale's, or the root one injection writes into); baseDir is what the reported path is relative to, so the message names the file the way its author does. Pass "" for baseDir to report relative to docsDir.
func CheckReservedPagePaths ¶
CheckReservedPagePaths refuses a page whose top-level segment is a reserved one, naming the page and the segment.
The paths are checked in sorted order, so a docs tree with two offending pages always names the same one.
func CleanupInjectedPosts ¶
CleanupInjectedPosts removes the post files InjectPostsIntoDocs wrote, and the "blog/" subdirectory under docsDir when it is left empty.
func CompressOutput ¶
CompressOutput writes a gzip and a brotli companion beside every compressible file under outputDir, and returns how many files it compressed.
brotli is compiled into this binary, so both companions are always written.
The tree is walked in sorted order, so a preview names the companions in the same order on every run.
func DefaultLocaleOf ¶
DefaultLocaleOf is the locale code a project's site-level pages are written in: the declared default if one is marked, else the first declared -- the same rule Build applies to the versioned tree.
func ExtractCriticalCSS ¶
ExtractCriticalCSS splits a theme stylesheet into its critical part and the whole sheet.
The critical part is everything above CriticalCSSMarker, right-trimmed. A sheet carrying no marker is treated as critical in full, which is the safe answer: a page then inlines more than it needs rather than painting unstyled.
func ExtractVersionContent ¶
func ExtractVersionContent(version string, config map[string]any, baseDir string, h *effects.Handle) (string, error)
ExtractVersionContent extracts a version's docs and source content out of its git tag into a cache directory, and returns that directory.
The tag is looked up as "v{version}" and then as "{version}". Its commit is resolved through "^{commit}", so an annotated tag is dereferenced to what it points at, and recorded in a ".hash" sentinel beside the extracted content: a tag still standing at the same commit is not extracted again.
The content is moved by streaming "git archive" into "tar -x", so nothing buffers the whole tree. The cache is one of selfdoc's uncommitted directories, so the derived ignore file inside the tool-state directory is what keeps it out of the repository.
Both docs roots are extracted: the handwritten pages the config names, and the generated pages committed beside them, so an archived version's build sees the same two roots the working tree's build does.
func GenerateAtomFeed ¶
func GenerateAtomFeed(opts FeedOptions, h *effects.Handle) (string, error)
GenerateAtomFeed writes the site's Atom feed and returns the path written.
Entries are ordered by date, most recent first. A post uses its declared publication date and a documentation page its modification date, which is what puts a newly published post at the top of a feed whose docs were built the same day.
func GenerateAuxiliaryFiles ¶
GenerateAuxiliaryFiles writes the files that belong to the site rather than to a page: the social cards, the sitemap, llms.txt and llms-full.txt, the Atom feed, the 404 page, the favicon, robots.txt and -- for a Cloudflare Pages deploy -- the _headers file.
It returns the paths written.
func GenerateFaviconSVG ¶
GenerateFaviconSVG generates a favicon from the project name's initial, on the accent colour.
A project with an empty name gets "D", for documentation.
func GenerateHeaders ¶
GenerateHeaders writes the Cloudflare Pages _headers file and returns the path written.
It carries the site's security headers and the immutable cache policy for everything whose bytes cannot change without its address changing.
func GenerateLLMSFullTxt ¶
func GenerateLLMSFullTxt(projectName string, markdownFiles []page.SourceFile) string
GenerateLLMSFullTxt renders llms-full.txt: the full text of every page as plain Markdown.
Each page's section opens with its title as a heading and a comment naming its source path, and the sections are separated by a thematic break.
func GenerateLLMSTxt ¶
func GenerateLLMSTxt( projectName string, markdownFiles []page.SourceFile, urlBuilder urls.URLBuilder, pageAddresses map[string]address.PageAddress, ) (string, error)
GenerateLLMSTxt renders llms.txt: a brief index naming every page, its title and its first paragraph.
pageAddresses maps every listed page's Markdown path to its address, and is required: a page's absolute URL is its mounted address, and this function has no way to work one out on its own.
func GenerateOGPNGBasic ¶
GenerateOGPNGBasic generates a 1200x630 PNG social card carrying no text.
The card is written by hand rather than through an image library: a light background derived from the accent colour, a 16-pixel accent bar across the top, and a striped accent band in the lower portion. accentColor is a "#rrggbb" string.
This is the only card path. The Python surface had a second one that drew the project name and the page title through an external renderer when it happened to be installed, which made a build's output depend on what was in the environment; the card a build emits is now the same card everywhere.
func GeneratePerLocaleSitemaps ¶
func GeneratePerLocaleSitemaps( outputDir string, localeCodes []string, perLocaleStableHTML map[string][]string, urlBuilder urls.URLBuilder, pageDates map[string]page.PageDates, h *effects.Handle, ) ([]string, error)
GeneratePerLocaleSitemaps writes one sitemap per locale at "<locale>/sitemap.xml", and returns the paths written in locale order.
func GenerateRobotsTxt ¶
func GenerateRobotsTxt(outputDir string, urlBuilder urls.URLBuilder, hasSitemapIndex bool, h *effects.Handle) (string, error)
GenerateRobotsTxt writes robots.txt and returns the path written.
The crawler policy itself is declared in the robots package, so this file and the assembly's site-wide robots.txt cannot drift apart. With hasSitemapIndex the file names sitemap-index.xml instead of sitemap.xml.
func GenerateSitemap ¶
func GenerateSitemap(htmlPaths []string, urlBuilder urls.URLBuilder, pageDates map[string]page.PageDates) string
GenerateSitemap renders a sitemap.xml document for the given HTML paths.
htmlPaths are output keys, which may carry a locale or version prefix while pageDates is keyed by the unprefixed Markdown path -- so a date lookup that misses retries against the path's last component and against everything below the first two prefix segments. The last-modified date is the page's modification date; a page with none gets a bare location entry.
func GenerateSitemapIndex ¶
func GenerateSitemapIndex(outputDir string, localeCodes []string, urlBuilder urls.URLBuilder, h *effects.Handle) (string, error)
GenerateSitemapIndex writes sitemap-index.xml at the output root, listing the per-locale sitemaps in sorted locale order, and returns the path written.
func InjectPostsIntoDocs ¶
func InjectPostsIntoDocs( dirPath string, cfg config.Config, docsDir string, includeDrafts bool, h *effects.Handle, ) ([]string, error)
InjectPostsIntoDocs writes the post pages into the docs tree so the normal build pipeline discovers them, and returns the absolute paths it wrote, in sorted order, for cleanup.
Posts are discovered from the configured posts directory and drafts are left out unless includeDrafts is set. Each post is written under "<docsDir>/blog/" and the listing at "<docsDir>/blog.md", which is emitted at "blog/". The written files are picked up by the docs walk and partitioned into the site-level page set, which is built with no mount at all -- so a post is at "blog/<slug>/" whichever build produced it.
It refuses first: an authored page on a reserved path is a file this function would overwrite and cleanup would then delete, so no build that could inject may proceed past one. Checking here rather than at each call site is what makes the destruction structurally impossible -- every build path reaches the tree through this function.
func IsSiteLevelPage ¶
IsSiteLevelPage reports whether a docs-relative page is site-level -- a post or their listing.
Site-level pages are built with no mount at all: the posts under "blog/<slug>.md" and the listing at "blog.md", which is emitted at "blog/" beside them.
func MakeURLBuilder ¶
func MakeURLBuilder(config map[string]any) urls.URLBuilder
MakeURLBuilder returns the URL builder a project's config asks for.
A topology block naming both a docs base and a slug gets the topology builder, which mounts the project under its slug and serves the site-level pages from the site root. Otherwise a declared base URL gets the simple builder. A config declaring neither gets nil, and every caller that emits an absolute URL refuses rather than inventing one.
func MinifyCSS ¶
MinifyCSS minifies CSS by removing comments, collapsing whitespace, and trimming the ends.
A regular-expression pass, which is enough for well-formed CSS and is what every generated stylesheet has been shipped through.
func MinifyHTML ¶
MinifyHTML minifies HTML by removing comments and collapsing the whitespace between tags and inside text nodes.
The content of pre, code, script and textarea elements is preserved verbatim: those are the elements whose whitespace is meaningful.
func PostDocsPayloads ¶
PostDocsPayloads returns the docs-tree Markdown for a set of published posts.
It maps a docs-relative path -- "blog/<slug>.md", plus "blog.md" for the listing, which is emitted at "blog/" -- to the Markdown that page is built from. Posts are site-level pages: they are built at "blog/<slug>/" under the output root, with no locale, project or version segment, and both the full build and the posts-only build emit them at that same address. This is the one place a post becomes a docs page: InjectPostsIntoDocs writes these payloads into the docs tree, and the in-memory render path hands the same payloads to BuildSingle as an overlay -- so both produce the same pages.
publishedPosts must already be filtered (drafts removed unless they were asked for) and ordered newest-first.
func PruneUnreferencedPagefindWidget ¶
PruneUnreferencedPagefindWidget deletes Pagefind's own search widget when no page in the tree loads it.
The indexer writes its widget beside the index whether or not anything references it, and a framework theme draws its own search surface over Pagefind's query API instead. What decides is therefore not the theme but the pages: a tree where nothing names the widget's bundle carries it as dead weight, and its stylesheets paint a design language those pages do not share. Reading the answer off the emitted HTML is also what makes this right for an assembly, where one tree can carry several themes and one page still loading the widget keeps it for everyone.
The index itself and pagefind.js -- the query API a palette calls -- are never touched.
It returns the paths removed, in the order page.PagefindUIAssets declares them.
func RenderPostListing ¶
RenderPostListing renders the Markdown listing page from published post metadata, frontmatter included.
publishedPosts must already be ordered newest-first and filtered -- no drafts unless drafts were asked for.
func ResolveLocaleDocsDir ¶
func ResolveLocaleDocsDir(dirPath, docsDirName, localeCode string, locales []map[string]any) (string, error)
ResolveLocaleDocsDir resolves the docs directory one locale's pages are read from.
A multi-locale project keeps them under "docs/<code>/", which must exist. A single-locale project need not: when its locale subdirectory is absent and "docs/" itself holds pages, that is the locale's directory.
func RunPagefind ¶
RunPagefind runs Pagefind over the built site to generate its search index.
Two invocations are tried in order -- the Python module ("python3 -m pagefind") and then the standalone binary ("pagefind") -- because the project installs whichever suits it. An installation that exists and fails is an error naming its stderr; no installation at all is an error naming how to install one.
An interpreter that does not carry the module counts as no installation and the next candidate is tried. The Python this replaces ran the module under its OWN interpreter (sys.executable), so the module was either importable or the whole program was, and the case could not arise; a Go binary asks whatever python3 is on PATH, and refusing at "No module named pagefind" instead of trying the standalone binary would refuse a machine that has Pagefind installed.
func SiblingsBlockRange ¶
SiblingsBlockRange is the half-open byte range the sibling block occupies in pageHTML, and reports whether the page carries one at all.
A page whose block is opened and never closed is reported as carrying none: nothing can be spliced out of a range with no end, and a truncated page is not one to write a second block onto either.
func VersionedHTMLPaths ¶
func VersionedHTMLPaths( buildDir, docsDirName, localeCode string, locales []map[string]any, cfg config.Config, ) (map[string]bool, error)
VersionedHTMLPaths lists the output keys of the version-scoped pages a docs tree would build.
A cheap scan -- walk the tree, read frontmatter, skip the site-level and "versioned: false" pages -- because the only question it answers is which versions hold a given page. The version picker asks that before offering a version, so it never links to a file no build wrote.
func WithRefreshedSiblings ¶
func WithRefreshedSiblings(pageHTML, siteHop string, siblings []SiblingProject) string
WithRefreshedSiblings is pageHTML carrying the sibling block rendered for siblings at siteHop, whatever it carried before.
This is the whole splice, in one place, because two callers need it: the build, which writes the block onto a page that has none, and the assembly's refresh pass, which regenerates it on pages earlier deploys wrote. The assembly is never rebuilt whole -- a project's subtree is replaced only when that project deploys -- so a block naming the membership of the day it was written outlives that membership on every other project's pages, and links a retired project's address until something rewrites it in place.
The three cases:
- The page carries a block: it is replaced by the rendered one, which is what makes the pass idempotent -- the same inputs render the same bytes.
- The page carries none: the block is written in front of the page footer, the position the build writes it at. A page with no footer element is left alone -- the wrapper writes one on every page it builds, and a fragment that has none is not a page this block belongs at the end of.
- There is nothing to list: an existing block is removed, footer and all else untouched, and no block is written.
Types ¶
type AuxiliaryOptions ¶
type AuxiliaryOptions struct {
// OutputDir is the site's output root.
OutputDir string
// ProjectName and Version name the project the site documents.
ProjectName string
Version string
// MarkdownFiles are every page the site published, which the social
// cards, llms.txt and the feed are built from.
MarkdownFiles []page.SourceFile
// HTMLPaths are the stable output keys the sitemap lists.
HTMLPaths []string
// BaseURL is the site's base address.
BaseURL string
// HasCustomCSS says whether the project ships a custom.css.
HasCustomCSS bool
// Repo is the repository URL.
Repo string
// URLBuilder builds the absolute URLs every generated document carries.
URLBuilder urls.URLBuilder
// Lang is the language tag the 404 page declares.
Lang string
// PageDates and Frontmatter are the per-page metadata the sitemap and
// the feed read.
PageDates map[string]page.PageDates
Frontmatter map[string]util.Frontmatter
// Description is the project-level description the feed subtitles.
Description string
// FeedURL is where the Atom feed sits relative to a page.
FeedURL string
// CriticalCSS is the stylesheet fragment the 404 page inlines.
CriticalCSS string
// AccentColor paints the social cards and the favicon.
AccentColor string
// ThemeMeta is the theme's metadata.
ThemeMeta *themes.Metadata
// Deploy is the config's deploy block, which decides whether a _headers
// file is written.
Deploy map[string]any
// FeedMaxEntries truncates the feed. Nil keeps every entry.
FeedMaxEntries *int
// HasSitemapIndex points robots.txt at the sitemap index instead of the
// single sitemap.
HasSitemapIndex bool
// MountLocale and MountProject are the mount coordinates the current
// pages sit under: the 404 sits at the output root, but the pages it
// links to live under a mount.
MountLocale string
MountProject string
// PageAddresses maps every page in MarkdownFiles to its address. It is
// required: the feed and llms.txt emit absolute page URLs, and a page's
// URL is its mounted address -- there is no sensible mountless answer
// to fall back on. Both emit the stable address, which is the one that
// keeps working.
PageAddresses map[string]address.PageAddress
}
AuxiliaryOptions is everything the site-level files are built from.
type BuildResult ¶
type BuildResult struct {
// HTMLFiles maps each page's output key -- the mount-prefixed path the
// file is written at -- to its full HTML document.
HTMLFiles map[string]string
// MarkdownFiles are the pass's resolved Markdown sources, sorted by
// docs-relative path.
MarkdownFiles []page.SourceFile
// Frontmatter maps a page's source path to its parsed metadata, with an
// entry only for a page that declares some.
Frontmatter map[string]util.Frontmatter
// PageDates maps a page's source path to the dates it states.
PageDates map[string]page.PageDates
// read too.
NavItems []page.NavItem
// ProjectName is the project's name.
ProjectName string
// Version is the version this pass built.
Version string
// Config is the config the pass ran under, locale docs directory
// included.
Config config.Config
// DocsDir is the directory the pass read its templates from.
DocsDir string
// OtherFiles are the non-Markdown assets under DocsDir, relative to it
// and sorted.
OtherFiles []string
// HasCustomCSS says whether the docs tree ships a custom.css.
HasCustomCSS bool
// RawThemeCSS is the theme's composed stylesheet, before minification.
RawThemeCSS string
// ThemeMeta is the theme's metadata.
ThemeMeta *themes.Metadata
// CriticalCSS is the minified above-the-fold fragment every page
// inlines.
CriticalCSS string
// ConfigDescription is the project-level description.
ConfigDescription string
// BaseURL is the site's base address, "" when the config declares none.
BaseURL string
// FeedURL is where the Atom feed sits relative to a page.
FeedURL string
// Lang is the language tag the pass's pages declare.
Lang string
// URLBuilder is the builder the pass's absolute URLs came from. It is
// nil on a result [BuildSingle] returned: the caller that needs one
// builds it from the config.
URLBuilder urls.URLBuilder
}
BuildResult is everything one locale-and-version pass built, handed back to the caller instead of written.
Build does all of the output IO; this type is what it writes from, and what the in-memory render path reads instead of a file.
func BuildSingle ¶
func BuildSingle(opts SingleOptions, h *effects.Handle) (BuildResult, error)
BuildSingle builds the HTML for a single version and locale of a project's docs.
It loads the config, resolves every template's directives, wraps each page in its chrome, adds the image dimensions read off the files on disk, and hands the whole result back: Build does the output IO.
One thing is written here, and only here: the staleness baselines under the hash store. Turn WriteBaselines off and the call touches nothing at all.
The mount is the single input that decides where pages land and how they reach the output root; the addressing authority turns it plus a page path into every address the page has.
type FeedEntry ¶
type FeedEntry struct {
// Date is the entry's date, in ISO form, which the feed sorts by.
Date string
// XML is the rendered entry element.
XML string
}
FeedEntry is one Atom entry: the date it sorts by and the XML that renders it.
func MakeFeedEntry ¶
MakeFeedEntry renders one Atom feed entry.
It takes abstract page metadata rather than raw Markdown, so the per-project feed and the assembly's site-wide one build their entries the same way. An entry with no summary omits the element rather than carrying an empty one.
type FeedOptions ¶
type FeedOptions struct {
// OutputDir is the site's output root, where feed.xml is written.
OutputDir string
// ProjectName and Description title and subtitle the feed.
ProjectName string
Description string
// MarkdownFiles are the pages the feed lists.
MarkdownFiles []page.SourceFile
// Frontmatter maps a page's path to its metadata. A page declaring
// "feed: false" is left out.
Frontmatter map[string]util.Frontmatter
// PageDates maps a page's path to its dates.
PageDates map[string]page.PageDates
// URLBuilder builds the absolute URLs the entries carry.
URLBuilder urls.URLBuilder
// PageAddresses maps every listed page to its address, and is required:
// an entry's link and id are its mounted address.
PageAddresses map[string]address.PageAddress
// MaxEntries truncates the feed to the most recent entries. Nil keeps
// every entry.
MaxEntries *int
// Now supplies the feed-level date for a project whose pages state
// none. The zero value takes the current time.
Now time.Time
}
FeedOptions is everything the Atom feed is built from.
type Options ¶
type Options struct {
// DirPath is the project root.
DirPath string
// Config is a pre-loaded config. Nil loads selfdoc.json from DirPath.
Config config.Config
// VersionFilter builds only the named version. Empty builds every
// configured version.
VersionFilter string
// LocaleFilter builds only the named locale. Empty builds every
// configured locale.
LocaleFilter string
// IncludeDrafts includes the draft posts in the output.
IncludeDrafts bool
// Target selects what is built: "posts" for a posts-only build, empty
// for a full one.
Target string
// Theme overrides the theme the config declares, for this build only.
// Empty means the config decides. Nothing is written back to
// selfdoc.json -- the override lives as long as the call does.
Theme string
// Stdout is where the build's progress lines go. Nil writes to the
// process's standard output.
Stdout io.Writer
// Siblings are the other projects published on the assembled site this
// build's output is grafted into. Each built page ends with a section
// linking them. Empty -- which is what a standalone build passes --
// emits no section: a project deployed on its own has no siblings.
Siblings []SiblingProject
// SiteName is the name of the assembled site this build's output is
// grafted into, which every page's document title ends with. Empty --
// which is what a standalone build passes -- ends a title at the
// project: a project deployed on its own has no site above it.
SiteName string
// Now supplies the date a page with no date and no file behind it
// carries. The zero value takes the current time.
Now time.Time
}
Options is everything one Build takes.
type Partition ¶
type Partition struct {
// Versioned are the pages emitted once per version.
Versioned map[string]bool
// Unversioned are the pages declaring "versioned: false", emitted once
// at the version-free mount.
Unversioned map[string]bool
// Site are the site-level pages -- the posts and their listing --
// emitted once with no mount at all.
Site map[string]bool
// UnversionedMarkdown and UnversionedFrontmatter carry the unversioned
// pages' resolved content and metadata, which every version's sidebar
// needs.
UnversionedMarkdown map[string]string
UnversionedFrontmatter map[string]util.Frontmatter
}
Partition is one docs tree's pages, split by how the build mounts them.
func PartitionPages ¶
func PartitionPages( cfg config.Config, docsDir, dirPath string, h *effects.Handle, ) (Partition, error)
PartitionPages partitions a docs tree's pages into the versioned, the unversioned and the site-level sets.
It resolves every page once and reads the "versioned" frontmatter key: a page without it, or with it set true, is versioned. A page under the posts prefix is neither -- it is a site-level page, built once with no mount at all, and comes back as its own set.
type SiblingProject ¶
type SiblingProject struct {
// Slug is the site segment the project is served under.
Slug string
// Name is the project's display name.
Name string
// Description is the project's one-line description, "" when its
// manifest states none.
Description string
}
SiblingProject is one other project published on the same assembled site.
It is what one line of the sibling block needs and nothing more: where the project is served, what it is called, and the one-line description its manifest carries.
func SiblingsFromManifests ¶
func SiblingsFromManifests( manifests []map[string]any, homeSlug, selfSlug string, ) []SiblingProject
SiblingsFromManifests is the sibling list for one project, read off the assembly's manifests.
Two projects are left out: the one the pages belong to, which does not link itself, and the home project, which is the site root every page already reaches rather than one of the tools the site publishes. A manifest with no slug names no address and is skipped.
type SingleOptions ¶
type SingleOptions struct {
// DirPath is the project root.
DirPath string
// Config is a pre-loaded config. Nil loads selfdoc.json from DirPath.
Config config.Config
// MountLocale is the locale segment of this pass's output mount, e.g.
// "en". Point it at "" for an unmounted pass; leave it nil to have the
// coordinate computed from the config alongside MountVersion.
MountLocale *string
// MountProject is the constituent-project segment of the mount on a
// unified site, "" on a standalone one.
MountProject string
// MountVersion is the version these pages are built from, e.g.
// "0.7.0". Point it at "" for pages that are not version-scoped; leave
// it nil to have the coordinate computed from the config alongside
// MountLocale. A version does not imply a version segment: the current
// version is emitted at the stable address.
MountVersion *string
// MountArchived marks this pass a superseded version, emitted under
// "v/<version>/" beside the stable tree.
MountArchived bool
// VersionOverride replaces the detected version string. Nil detects it
// from the project's manifests.
VersionOverride *string
// LocaleOverride is the locale this pass builds, which prefixes the
// staleness baselines and can become the pages' language tag. Nil means
// the pass is not locale-scoped.
LocaleOverride *string
// AvailableVersions and AvailableLocales are the configured versions
// and locales the two pickers offer.
AvailableVersions []map[string]any
AvailableLocales []map[string]any
// VersionPages maps a version to the output keys it holds, so the
// version picker never offers a version that does not have the page.
VersionPages map[string]map[string]bool
// CurrentLocale is the locale being built, for the locale picker's
// selected option and the locale facet.
CurrentLocale string
// PageFilter keeps only the named pages. Nil builds every page the walk
// found.
PageFilter map[string]bool
// UnversionedMarkdown and UnversionedFrontmatter are the persistent
// pages every version's sidebar shows. They reach the navigation and
// nothing else.
UnversionedMarkdown map[string]string
UnversionedFrontmatter map[string]util.Frontmatter
// OverlayDocs maps a docs-relative .md path to Markdown source held in
// memory. Entries are resolved like files on disk and override
// same-named files, so pages that were never written can be built.
OverlayDocs map[string]string
// WriteBaselines advances the staleness baselines under
// the hash store. False makes the whole call write nothing at all,
// which -- together with OverlayDocs -- is what makes an in-memory
// render possible.
WriteBaselines bool
// Siblings are the other projects published on the assembled site this
// build's output is grafted into. Each built page ends with a section
// linking them. Empty -- which is what a standalone build passes --
// emits no section at all: a project deployed on its own has no
// siblings, and there is nothing to invent them from.
Siblings []SiblingProject
// SiteName is the name of the assembled site this build's output is
// grafted into, which every page's document title ends with. It is
// stated by the caller for the same reason Siblings is: a standalone
// build has no site around it, states none, and its pages end their
// titles at the project.
SiteName string
// Now supplies the modification date of a page that states none and has
// no file behind it. The zero value takes the current time.
Now time.Time
}
SingleOptions is everything one BuildSingle pass takes.
It mirrors the keyword arguments of the Python function it replaces, with two omissions: that function also took the current version and an is-latest flag, and passed both to a renderer that read neither.
Start from NewSingleOptions rather than from the zero value: the baselines are written by default, and a zero-valued struct would silently stop advancing them.
func NewSingleOptions ¶
func NewSingleOptions() SingleOptions
NewSingleOptions returns the options one pass starts from: the baselines are advanced, which is what every build does.
func SiteLevelBuildArgs ¶
func SiteLevelBuildArgs(cfg config.Config, docsDirName string) SingleOptions
SiteLevelBuildArgs returns the SingleOptions every site-level page is built with.
A post is one page with one address, and three paths produce it: the full build's site-level pass, the posts-only target the assembly runs when nothing but a post changed, and the in-memory renderer an editor previews with. Whichever ran last decides what the site serves, so they cannot differ -- and the way to guarantee that is for the arguments to have one definition rather than three copies.
Site-level means no mount and no version segment: the page is served from the site root, not from the project's subtree and not from an archive prefix. It still carries the project's default locale, which is what puts it in a locale search filter.
The caller sets DirPath and whichever of PageFilter and OverlayDocs its own path needs.