Skip to content
internal/blog/posts
On this page

What makes a Markdown file a blog post: the required frontmatter, the directive declaration, the derived slug, and that slug's immutability once published.

#internal/blog/posts

#internal/blog/posts

Package posts discovers and validates a project's blog posts.

A post is a dated Markdown file with frontmatter, sitting under the posts directory. This package is the whole of what makes one a post: the required fields, the required directive declaration, the derived slug and its immutability once published, and the type and version keys a post carries without declaring them.

#Two callers, one meaning

[Discover] reads the files on disk; [Parse] takes one post's source as a string. The editor's render path calls Parse on a buffer that may never be saved, so both agree on what a post's source means -- there is one definition of a valid post rather than one per entry point.

#The refusals carry coordinates

Every refusal is a [PostError] naming the post's path relative to the posts directory, and the line inside the post file when the defect sits at one. The check surface turns one of these into a POST diagnostic, and a diagnostic's file and line are read by editors, CI annotations and the JSON output -- none of which parse prose.

#PostError

Go go
type PostError struct

PostError reports an invalid post, with the coordinates of where it is invalid.

Path is relative to the posts directory, as a Post's own path is. Line is the post file's own line number, or nil for a defect that sits at no particular line (a missing frontmatter field).

#Post

Go go
type Post struct

Post is one post's metadata, in the shape the build, the listing pages and the editor read it.

#ManifestPosts

Go go
func ManifestPosts(all []Post) []manifest.Post

ManifestPosts converts a whole discovery result for the manifest writer, keeping the order it came in.

#Parse

Go go
func Parse(raw, relPath, publishedSlug string) (Post, error)

Parse parses and validates one post's Markdown source.

relPath is the post's path relative to the posts directory; it is named in every refusal and carried on the result. publishedSlug is the slug this post was published under, when it has one -- a different derived slug is a slug immutability violation. Pass "" when the post has never been published.

#Discover

Go go
func Discover(postsDir, manifestPath string, handle *effects.Handle) ([]Post, error)

Discover discovers, validates and returns the posts under postsDir, sorted newest-first and then by slug.

A postsDir that is not a directory holds no posts, which is an answer rather than a failure.

manifestPath optionally names an existing manifest file. When it is given, slug immutability is enforced against the COMMITTED manifest read out of git HEAD rather than the copy on disk, because gen may already have rewritten that copy with the new slug by the time this runs. A directory that is not a repository, a repository with no commits, and a manifest that was never committed each leave the check with nothing to compare against, and it is skipped.

Files are read in sorted order, so a duplicate-slug refusal always names the same pair in the same direction. The Python walked in directory-listing order and could name either post as the second one.

#PostError.Error

Go go
func (e *PostError) Error() string { return e.Message }

Error renders the refusal.

#Post.ManifestPost

Go go
func (p Post) ManifestPost() manifest.Post

ManifestPost narrows p to the slice a project's manifest records.

Search