content

package
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Aug 6, 2026 License: MIT Imports: 28 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func ApplyDefaults

func ApplyDefaults(fm map[string]interface{}, schema *engine.FrontmatterSchema) map[string]interface{}

ApplyDefaults fills in missing frontmatter fields from schema defaults. Returns a new map (does not mutate the input).

func ClassifyLang

func ClassifyLang(cf *ContentFile, languages map[string]bool, defaultLang string)

ClassifyLang sets the Lang, LangRelPath, and adjusts CollectionName on a ContentFile based on whether its first path segment matches a configured language code.

For single-language sites (languages is nil/empty), this is a no-op.

func ClassifyVersion

func ClassifyVersion(cf *ContentFile, versionIDs map[string]map[string]bool)

ClassifyVersion sets the Version and VersionRelPath on a ContentFile based on whether the path segment after the collection name matches a configured version ID. Must be called after ClassifyLang.

For single-version sites (versionIDs is nil/empty), this is a no-op.

func ComputePatternPermalink(pattern string, vars PermalinkVars) string

ComputePatternPermalink generates a permalink from a pattern string. Supported variables: :slug, :year, :month, :day, :section, :collection, :title

func ComputePermalink(contentDir, filePath string) string

func ComputePermalinkFromRelPath

func ComputePermalinkFromRelPath(relPath string) string

ComputePermalinkFromRelPath computes a permalink from a forward-slash relative path (e.g. cf.LangRelPath). Unlike ComputePermalink, this operates on a path already stripped of any language directory prefix, producing a language-free RelPermalink that is identical across translations.

func DetectUnknownFields

func DetectUnknownFields(fmMap map[string]any, schema *engine.FrontmatterSchema, taxCfg map[string]config.TaxonomyConfig, filePath string) []engine.ValidationWarning

DetectUnknownFields warns about frontmatter keys not recognized by Sarde. Schema-defined custom fields, taxonomy keys from taxCfg, and children of cascade/params are excluded.

func ExtractFirstH1

func ExtractFirstH1(markdown string) string

ExtractFirstH1 finds the first Markdown H1 heading (# Title) in raw markdown. Returns empty string if no H1 is found.

func ExtractNumericPrefix

func ExtractNumericPrefix(name string) (weight int, slug string, found bool)

ExtractNumericPrefix parses a leading numeric prefix from a filename (without extension). "01-intro" returns (1, "intro", true). "intro" returns (0, "intro", false).

func FilenameSlug

func FilenameSlug(filename string) (slug string, weight int)

FilenameSlug extracts a slug from a filename, stripping extension and numeric prefix.

func FilenameToTitle

func FilenameToTitle(filename string) string

FilenameToTitle converts a filename to a human-readable title. Strips extension, strips numeric prefix, replaces hyphens/underscores with spaces, title cases.

func GetLastUpdated

func GetLastUpdated(filePath, strategy string, idx *GitLastModIndex) *time.Time

GetLastUpdated returns the "last updated" timestamp for a file according to the configured strategy. It returns nil when disabled or when no timestamp can be determined.

Strategies:

  • "false" / "off" / "none" — disabled, returns nil
  • "git" (default) — commit time, falls back to mtime when unavailable
  • "mtime" — file modification time

The git strategy has three cases depending on idx:

  • nil index: resolve per file (one subprocess), for callers with no index
  • index present but unavailable: git was already probed and found unusable, so fall straight back to mtime rather than retrying per file
  • index available: O(1) map lookup, no subprocess

func HasIgnoredSegment added in v1.0.0

func HasIgnoredSegment(rel string) bool

HasIgnoredSegment reports whether any directory segment of the slash-separated content-relative path is ignored, or its leaf is an ignored file. Used by the incremental-rebuild path, which resolves single changed files without a directory walk.

func IsExpired

func IsExpired(expiryDate time.Time, now time.Time) bool

IsExpired returns true if expiryDate is non-zero and not in the future.

func IsIgnoredDirName added in v1.0.0

func IsIgnoredDirName(name string) bool

IsIgnoredDirName reports whether a directory is excluded from content discovery. Dot- and underscore-prefixed directories (.trash, .obsidian, _drafts) are never content — the same convention the collection enumerators in internal/collection and internal/project apply.

func IsIgnoredFileName added in v1.0.0

func IsIgnoredFileName(name string) bool

IsIgnoredFileName reports whether a file is excluded from discovery. Only dot-prefixed (hidden) files are skipped — underscore-prefixed files such as _index.md are meaningful content.

func IsScheduled

func IsScheduled(publishDate time.Time, now time.Time) bool

IsScheduled returns true if publishDate is non-zero and in the future.

func LoadSchema

func LoadSchema(collectionDir string) (*engine.FrontmatterSchema, error)

LoadSchema reads config.yaml from a collection directory and returns the schema. Returns (nil, nil) if no config file exists.

func NormalizePermalink(permalink string) string

NormalizePermalink ensures a permalink has a trailing slash (unless it's a file path with extension).

func ParseAll

func ParseAll(raw []byte) (map[string]interface{}, *engine.Frontmatter, string, int, error)

ParseAll parses raw file bytes into both an untyped map (for schema validation) and a typed Frontmatter struct. For YAML input (the common case), the struct is unmarshaled directly from the raw frontmatter bytes, avoiding a redundant marshal+unmarshal round-trip.

func ParseFrontmatter

func ParseFrontmatter(raw []byte) (*engine.Frontmatter, string, error)

ParseFrontmatter is a convenience function that parses raw file bytes into a typed Frontmatter struct and the Markdown body. It handles all three frontmatter formats (YAML, TOML, JSON) uniformly by converting through YAML.

func PrefixPermalink(permalink, lang, defaultLang string) string

ComputePermalink returns the clean URL for a content file. All permalinks end with "/" and use forward slashes.

Examples:

content/_index.md              → "/"
content/about.md               → "/about/"
content/docs/_index.md         → "/docs/"
content/docs/getting-started.md → "/docs/getting-started/"
content/docs/guide/index.md    → "/docs/guide/"

PrefixPermalink prepends a language prefix to a permalink for non-default languages. Used when generating fallback pages that need language-prefixed URLs. For the default language, it returns the permalink unchanged.

func ShouldExclude

func ShouldExclude(draft bool, publishDate, expiryDate time.Time, includeDrafts, includeFuture, includeExpired bool, now time.Time) bool

ShouldExclude returns true if a page should be excluded from output based on draft status, scheduling, and expiry.

func Slugify

func Slugify(s string) string

Slugify converts a string to a URL-safe slug. Lowercase, spaces/underscores become hyphens, non-alphanumeric stripped, collapsed.

func ValidatePageFields

func ValidatePageFields(page *engine.Page, fm *engine.Frontmatter) []engine.ValidationWarning

func VersionFreeRelPath

func VersionFreeRelPath(cf *ContentFile) string

VersionFreeRelPath returns a LangRelPath with the version segment removed. Used for computing a version-free RelPermalink.

"docs/v1/guides/auth.md" → "docs/guides/auth.md"
"docs/intro.md"          → "docs/intro.md" (unversioned, unchanged)

Types

type Collision

type Collision struct {
	Permalink   string
	KeptFile    string // first page registered at this URL
	DroppedFile string // a later page that resolved to the same URL
}

Collision records two distinct pages that resolve to the same Permalink. The first page registered at a URL is kept; later pages are dropped (first-match semantics). These are accumulated rather than logged inline so the builder can dedupe and cap them once per build (see emitCollisionWarnings).

type ContentFile

type ContentFile struct {
	FilePath       string          // absolute path
	RelPath        string          // relative to content dir (forward slashes)
	Kind           engine.NodeKind // home, section, page, bundle, standalone
	CollectionName string          // top-level dir name, "" for root-level files
	Slug           string          // derived from filename
	Order          int             // from numeric prefix
	IsBundle       bool            // true if index.md with sibling assets
	BundleAssets   []string        // sibling non-.md files (bundles only)
	Lang           string          // language code (set by i18n detector)
	LangRelPath    string          // relative path within language root (for translation matching)
	Version        string          // version ID (set by version detector), e.g. "v1"
	VersionRelPath string          // path within the version root (cross-version key)
}

ContentFile holds metadata about a discovered content file.

type GitLastModIndex added in v1.1.0

type GitLastModIndex struct {
	// contains filtered or unexported fields
}

GitLastModIndex holds the most recent commit time for each content path, built from a single `git log` walk instead of one subprocess per file.

A nil index means no index was built and callers should use the per-file path. A non-nil index with available == false means git was probed and found unusable; callers must fall straight back to mtime rather than retrying per file.

func BuildGitLastModIndex added in v1.1.0

func BuildGitLastModIndex(contentDir string, wantedPaths []string) (*GitLastModIndex, error)

BuildGitLastModIndex walks git history once for contentDir and records the most recent commit time for every path in wantedPaths that git knows about.

It never fails the build: any git problem yields an index with available == false plus a descriptive error the caller folds into a single build warning.

func (*GitLastModIndex) Available added in v1.1.0

func (idx *GitLastModIndex) Available() bool

Available reports whether the index holds usable git data.

func (*GitLastModIndex) Lookup added in v1.1.0

func (idx *GitLastModIndex) Lookup(absPath string) (time.Time, bool)

Lookup returns the most recent commit time for absPath. The second result is false when the path is untracked, was deleted from git after its last commit (tombstoned), or no index is available. Renamed files resolve normally: the walk keys the rename destination, so they carry the rename-commit time.

func (*GitLastModIndex) Shallow added in v1.1.0

func (idx *GitLastModIndex) Shallow() bool

Shallow reports whether the repository is a shallow clone, in which case history predating the shallow boundary is missing and affected pages fall back to mtime.

func (*GitLastModIndex) Stale added in v1.1.0

func (idx *GitLastModIndex) Stale() bool

Stale reports whether HEAD moved since the index was built, which happens when a commit lands outside the dev server (for example in another terminal). One `git rev-parse`, no history walk.

type Inferrer

type Inferrer struct {
	// LastUpdatedStrategy selects how missing Updated timestamps are resolved:
	// "git" (via `git log`), "mtime" (default), or "false"/"off"/"none" (disabled).
	LastUpdatedStrategy string

	// GitIndex is the batched git-history snapshot used by the "git" strategy.
	// Nil falls back to resolving each file with its own subprocess.
	GitIndex *GitLastModIndex
}

Inferrer fills missing frontmatter values using filesystem metadata. This is the "zero-config magic" — users get sensible defaults without specifying title, date, weight, or slug in frontmatter.

func (*Inferrer) Infer

func (inf *Inferrer) Infer(page *engine.Page, filePath string) error

Infer populates empty fields on a Page from the filesystem and content.

Inference cascade:

  • Title: frontmatter �� first H1 in RawContent → filename title-cased
  • Date: frontmatter → file modification time
  • Updated: frontmatter → git commit time or file mtime, per LastUpdatedStrategy
  • Weight: frontmatter → numeric prefix from filename → 0
  • Slug: frontmatter → filename with prefix stripped, slugified
  • Template: "splash" for home pages if not set

type PageIndex

type PageIndex struct {
	// contains filtered or unexported fields
}

PageIndex provides O(1) lookups of pages by permalink, slug, heading ID, and lane-scoped RelPermalink for internal link resolution.

func BuildPageIndex

func BuildPageIndex(pages []*engine.Page) *PageIndex

BuildPageIndex constructs a PageIndex from all pages. The bySlug map uses first-match semantics for duplicate slugs. The byLane map indexes each page by its RelPermalink within its (lang, version) lane.

func (*PageIndex) AddAssets

func (idx *PageIndex) AddAssets(dir string)

AddAssets walks a public directory and indexes all files as root-relative paths.

func (*PageIndex) Collisions

func (idx *PageIndex) Collisions() []Collision

Collisions returns the distinct-page permalink collisions recorded during BuildPageIndex (first-match kept). Empty when no two pages share a URL.

func (*PageIndex) CopyAssetsFrom added in v1.0.0

func (idx *PageIndex) CopyAssetsFrom(prev *PageIndex)

CopyAssetsFrom copies another index's asset set. Used by the incremental rebuild's body-only fast path, which skips the public/ directory walk: public file changes never route through ContentRebuild (the dev-server watcher classifies them as ChangeStatic, which take the full-build path), so the previous build's asset set is still valid.

func (*PageIndex) CopyHeadingsFrom added in v1.0.0

func (idx *PageIndex) CopyHeadingsFrom(prev *PageIndex, exclude map[string]struct{})

CopyHeadingsFrom copies heading entries from a previous build's PageIndex, skipping any permalink in exclude. Used by incremental rebuilds to reuse unchanged pages' headings; changed pages populate their own entries afterward via SetHeadings.

func (*PageIndex) HasAsset

func (idx *PageIndex) HasAsset(path string) bool

HasAsset reports whether a public asset with the given root-relative path exists.

func (*PageIndex) HasHeading

func (idx *PageIndex) HasHeading(permalink, headingID string) bool

HasHeading reports whether the given heading ID exists on the page. Safe for concurrent use.

func (*PageIndex) HasPage

func (idx *PageIndex) HasPage(permalink string) bool

HasPage reports whether a page with the given permalink exists.

func (*PageIndex) HeadingsFor

func (idx *PageIndex) HeadingsFor(permalink string) []string

HeadingsFor returns the heading IDs for a page, or nil if not set.

func (idx *PageIndex) LookupByPermalink(permalink string) *engine.Page

LookupByPermalink returns the page with the given permalink, or nil.

func (*PageIndex) LookupBySlug

func (idx *PageIndex) LookupBySlug(slug string) *engine.Page

LookupBySlug returns the first page matching the given slug, or nil.

func (*PageIndex) LookupInLane

func (idx *PageIndex) LookupInLane(relPermalink, lang, version string) *engine.Page

LookupInLane returns the page with the given RelPermalink in the specified (lang, version) lane. Returns nil if not found.

func (*PageIndex) PageCount

func (idx *PageIndex) PageCount() int

PageCount returns the number of indexed pages.

func (idx *PageIndex) Permalinks() []string

Permalinks returns all indexed permalinks. Used for testing and debugging.

func (*PageIndex) SetHeadings

func (idx *PageIndex) SetHeadings(permalink string, headingIDs []string)

SetHeadings stores heading IDs for a page. "_top" is always prepended. Safe for concurrent use.

type Parser

type Parser struct{}

Parser auto-detects YAML (---), TOML (+++), and JSON ({}) frontmatter delimiters.

func (*Parser) Parse

func (p *Parser) Parse(raw []byte) (map[string]interface{}, string, error)

Parse splits raw file bytes into a frontmatter map and Markdown body. Returns an empty map and the full content as body if no frontmatter is found.

type PermalinkVars

type PermalinkVars struct {
	Slug       string
	Year       string
	Month      string
	Day        string
	Section    string
	Collection string
	Title      string
}

PermalinkVars holds the values available for pattern interpolation.

type Scanner

type Scanner struct {
	Languages   map[string]bool            // configured language codes (nil = single-language)
	DefaultLang string                     // default language code
	VersionIDs  map[string]map[string]bool // collection name → set of version IDs (nil = no versioning)
}

Scanner walks the content directory and returns file paths grouped by collection.

func (*Scanner) ClassifyFile

func (s *Scanner) ClassifyFile(contentDir, filePath string) (ContentFile, error)

ClassifyFile constructs a ContentFile for a single file path without walking the entire content directory. Used by incremental rebuild.

func (*Scanner) Discover

func (s *Scanner) Discover(contentDir string) (map[string][]string, error)

Discover walks contentDir and returns file paths grouped by collection name. Root-level files (standalone, home) are grouped under the "" key.

func (*Scanner) DiscoverFiles

func (s *Scanner) DiscoverFiles(contentDir string) ([]ContentFile, error)

DiscoverFiles walks contentDir and returns a richer ContentFile for each .md file found.

type Transformer

type Transformer struct {
	SummaryLength int // max words in auto-generated summary (from config)
}

Transformer enriches a Page with computed fields: word count, reading time, and summary.

func (*Transformer) Transform

func (t *Transformer) Transform(page *engine.Page) error

Transform computes WordCount, ReadingTime, and Summary for a page.

type Validator

type Validator struct{}

Validator validates frontmatter against a collection's schema definition.

func (*Validator) Validate

func (v *Validator) Validate(fm map[string]interface{}, schema *engine.FrontmatterSchema) []engine.ValidationWarning

Validate checks frontmatter against a schema and returns warnings. A nil schema means no validation — returns nil. Never blocks the build; all issues are warnings.

Directories

Path Synopsis
extensions/blockutil
Package blockutil provides shared helpers for container-style block directive parsers.
Package blockutil provides shared helpers for container-style block directive parsers.
extensions/codediff
Package codediff is a stub extension for organizational completeness.
Package codediff is a stub extension for organizational completeness.
extensions/genericdirective
Package genericdirective is the goldmark side of site- and theme-authored generic directives (internal/directive): one block parser and renderer handle every registered ::: directive, dispatching on the fence name.
Package genericdirective is the goldmark side of site- and theme-authored generic directives (internal/directive): one block parser and renderer handle every registered ::: directive, dispatching on the fence name.

Jump to

Keyboard shortcuts

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