downcache

package module
v0.0.2 Latest Latest
Warning

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

Go to latest
Published: Sep 3, 2024 License: Apache-2.0 Imports: 21 Imported by: 2

README

DownCache

Status: Experimental

DownCache is a Go package that helps you organize, index, and search collections of Markdown files. It’s useful for projects with many Markdown posts, such as static site generators, documentation systems, or content management systems. It uses theyuin/goldmark package to convert Markdown to HTML.

What it does

  • Indexes markdown files, including their frontmatter metadata
  • It lets you search through all your markdown content
  • It categorizes posts (e.g., pages, posts, custom types) based on where they're stored and what's in their frontmatter
  • Supports both full and incremental reindexing to keep your index up-to-date
  • Uses BBolt to cache the markdown content and frontmatter for fast access
  • Uses Bleve to index and search through the markdown content
  • It can be extended with custom post types and frontmatter parsing rules
  • Takes inspiration from IndieWeb microformats for frontmatter naming and structure
  • Converts markdown content to HTML using the yuin/goldmark package
  • Supports creating, updating, and deleting markdown files and updating the indexes accordingly

It's designed to augment an existing Go application, so you can use it to add search and organization features to your Markdown-based projects. It doesn't handle routing, serving, or rendering HTML but can help you build those features into your application. It does not provide a user interface for managing content but can be used to build one.

Why?

I had a series of sites to build and wanted to use markdown files to store the content. I also wanted to search through the content and organize it. In addition, I wanted to add custom metadata to the Markdown files and make that metadata searchable. This package enables me to keep the posts in plaintext markdown files and still search through them from a web interface without needing a separate database or external search engine. The Markdown indexing and searching are ephemeral and can be rebuilt at any time.

Issues I wanted to address:
  1. Keep all content in plaintext markdown files, as the source of truth
  2. Use a fast, embedded database for caching converted content and metadata
  3. Find specific content across many files quickly (e.g., searching full-text, tags, or other metadata)
  4. Organize posts based on their type or other metadata
  5. Handle different types of posts (like articles, pages, notes, bookmarks?) in one system
  6. Use microformats for frontmatter to make it easier to work with the data
  7. Convert markdown content to HTML for display
  8. Have the ability to create, update, and delete Markdown posts programmatically, and have the indexes updated accordingly

Getting started

Here's a quick example of how to use it:

package main

import "github.com/hypergopher/downcache"

func main() {
	// A directory with markdown files
	markPath := "/path/to/markdown"

	// A directory to store the bbolt and bleve indexes
	dataPath := "/path/to/data"

	// A set of authors to associate with the markdown files
	authors := map[string]downcache.Author{
		"author1": {
			Name:      "Author 1",
			AvatarURL: "/images/author1.jpg",
			Links: []downcache.AuthorLink{
				{
					Name: "Mastodon",
					Icon: "mastodon",
					URL:  "https://example.social/@author1",
				},
			},
		},
	}

	// A set of taxonomies to associate with the markdown files
	taxonomies := map[string]string{
		"tags":       "tag",
		"categories": "category",
	}

	hd, err := downcache.NewDownCache(downcache.Options{
		MarkDir:      markPath,
		DataDir:      dataPath,
		Authors:      authors,
		Taxonomies:   taxonomies,
		ClearIndexes: true,
		Reindex:      true,
		Logger:       nil,
	})

	defer hd.Close()

	// Index everything
	hd.Reindex()

	// Get a post
	paginator, err := hd.GetPost("path/to/post-slug")

	// Get all articles (paginated)
	paginator, err := hd.GetPosts(downcache.FilterOptions{
		PageNum:              1,
		PageSize:             10,
		FilterByPostType: downcache.PostTypePost,
	})

	// Search for posts
	paginator, err := hd.GetPosts(downcache.FilterOptions{
		PageNum:              1,
		PageSize:             10,
		FilterByPostType: downcache.PostTypePost,
		FilterBySearch:       "your search query",
	})

	// Get posts by tag
	paginator, err := hd.GetPosts(downcache.FilterOptions{
		PageNum:    1,
		PageSize:   10,
		FilterType: downcache.FilterTypeTaxonomy,
		FilterKey:  "tags",
		FilterTerm: "tag3",
	})

	// Get posts by author
	paginator, err := hd.GetPosts(downcache.FilterOptions{
		PageNum:    1,
		PageSize:   10,
		FilterType: downcache.FilterTypeAuthor,
		FilterTerm: "author1",
	})
}

Where you might use this

  • In a static site generator to add search and help organize content
  • For a documentation system to manage and search through lots of docs
  • As part of a content management system for handling blog posts or articles
  • To create searchable collections of markdown-based knowledge articles

License

This project is under the Apache 2.0 License - check out the LICENSE file for details.

Frontmatter

The frontmatter for each markdown file can be in YAML or TOML format. Here's an example of what it might look like:

---
name: "Page 1"
summary: "Page 1 summary"
status: "published"
published: "2021-01-01T00:00:00Z"
authors:
  - author1
taxonomies:
  categories:
    - cat1
    - cat2
  tags:
    - tag1
    - tag2
---
+++
name = "Page 1"
summary = "Page 1 summary"
status = "published"
published = "2021-01-01T00:00:00Z"
authors = ["author1"]

[taxonomies]
categories = ["cat1", "cat2"]
tags = ["tag1", "tag2"]

[properties]
key1 = "value1"
key2 = "value2"
+++
Available frontmatter fields

Frontmatter fields adhere to the h-entry microformat. The following fields are available:

  • authors (array of strings): The authors of the post. Each string represents a key in the Authors map passed into DownCache.
  • featured (bool): Whether the post is featured
  • photo (string): The URL of a featured image
  • name (string): The name/title of the post
  • properties (map[string]any): Arbitrary key-value pairs for additional metadata, such as extra microformat properties.
  • published (time.Time): The time the post was published (Use RFC3339 format like "2006-01-02T00:00:00Z" or " 2006-01-02")
  • status (string): The status of the post (draft or published). If empty, the post is considered published.
  • subtitle (string): A subtitle for the post
  • summary (string): A summary of the post
  • taxonomies (map[string][]string): The taxonomies associated with the post
  • visibility (string): The visibility of the post (public, private, or unlisted). If empty, the post is considered public.

When working with status (published, draft) or visibility (public, private, unlisted), it is up to the caller to interpret these values as needed and to show/hide posts accordingly.

(Optional) Dates in filenames

If you want to use optional dates in your filenames, you can use the following format:

YYYY-MM-DD-post-slug.md

This will allow DownCache to extract the date from the filename and use it as the published date for the post.

If a published field is present in the frontmatter, it will take precedence over the date in the filename.

The published date will not be set if no date is found in the filename or frontmatter.

The slug will always have the date in the filename, but you can use the following methods to get a slug without the embedded filename date. Depending on your needs, however, this may cause conflicts if you have multiple posts with the same slug but different dates.

  • SlugWithoutDate() on a Post struct. For example, foobar/2024-08-21-post-slug would become foobar/post-slug.
  • SlugWithYear() on a Post struct. For example, foobar/2024-08-21-post-slug would become 2024/foobar/post-slug.
  • SlugWithYearMonth() on a Post struct. For example, foobar/2024-08-21-post-slug would become 2024/08/foobar/post-slug.
  • SlugWithYearMonthDay() on a Post struct. For example, foobar/2024-08-21-post-slug would become 2024/08/21/foobar/post-slug.

TODO

  • Improve documentation
  • Implement incremental reindexing
  • Align better with microformat properties

Possible future features

  • Additional microformat properties
    • location (string): The location the entry was posted from
    • syndication (array of strings): URLs of syndicated copies of the entry
    • in-reply-to (string): URL of the post this post is in reply to
    • repost-of (string): URL of the post this post is a repost of
    • like-of (string): URL of the post this post is a like of
    • bookmark-of (string): URL of the post this post is a bookmark of
    • rsvp (string): RSVP status of the post
    • video (string): URL of a video related to the post
  • Custom post types. This may already be handled by the the TypeRules field in the Options struct.
  • Custom frontmatter parsing rules
  • Custom query parsing rules
  • Implement a Micropub endpoint
  • Implement a JSON Feed endpoint
  • Implement a RSS Feed endpoint

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidPostMeta = errors.New("invalid post metadata")
)

Functions

func EstimateReadingTime

func EstimateReadingTime(content string) string

EstimateReadingTime estimates the reading time of the content.

func GenerateETag

func GenerateETag(content string) string

GenerateETag generates an ETag for the content.

func IsValidPostPath

func IsValidPostPath(path string) bool

func PostPathID added in v0.0.2

func PostPathID(postType, slug string) string

PostPathID returns the unique identifier for a page of the specified type and slug

Types

type Author

type Author struct {
	Username  string       `json:"username" yaml:"username" toml:"username"`
	Name      string       `json:"name" yaml:"name" toml:"name"`
	Country   string       `json:"country" yaml:"country" toml:"country"`
	Active    bool         `json:"active" yaml:"active" toml:"active"`
	Bio       string       `json:"bio" yaml:"bio" toml:"bio"`
	AvatarURL string       `json:"avatarURL" yaml:"avatarURL" toml:"avatarURL"`
	Links     []AuthorLink `json:"links" yaml:"links" toml:"links"`
}
type AuthorLink struct {
	Name string `json:"name" yaml:"name" toml:"name"`
	Icon string `json:"icon" yaml:"icon" toml:"icon"`
	URL  string `json:"url" yaml:"url" toml:"url"`
}

type CacheStore added in v0.0.2

type CacheStore interface {
	// Init initializes the post store, such as creating the necessary tables or indexes.
	Init() error
	// Clear clears all data from the post store and resets the store.
	Clear(ctx context.Context) error
	// Close closes the post store.
	Close() error
	// Create creates a new post.
	Create(ctx context.Context, post *Post) (*Post, error)
	// Delete deletes a post.
	Delete(ctx context.Context, postType, slug string) error
	// Get retrieves a post by its slug.
	Get(ctx context.Context, postType, slug string) (*Post, error)
	// GetTaxonomies returns a list of taxonomies.
	GetTaxonomies(ctx context.Context) ([]string, error)
	// GetTaxonomyTerms returns a list of terms for a given taxonomy.
	GetTaxonomyTerms(ctx context.Context, taxonomy string) ([]string, error)
	// Search searches for posts based on the provided filter options.
	Search(ctx context.Context, opts FilterOptions) ([]*Post, int, error)
	// Update updates an existing post.
	Update(ctx context.Context, oldType, oldSlug string, post *Post) error
}

type DefaultMarkdownProcessor added in v0.0.2

type DefaultMarkdownProcessor struct{}

DefaultMarkdownProcessor is the default implementation of the MarkdownProcessor interface

func (DefaultMarkdownProcessor) GenerateFrontmatter added in v0.0.2

func (d DefaultMarkdownProcessor) GenerateFrontmatter(meta *PostMeta, format FrontmatterFormat) (string, error)

func (DefaultMarkdownProcessor) Process added in v0.0.2

func (d DefaultMarkdownProcessor) Process(input []byte) (*Post, error)

type DownCache

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

DownCache is the main entry point for the markdown cache system

func NewDownCache

func NewDownCache(fs MarkdownFS, store CacheStore) *DownCache

func (*DownCache) Create added in v0.0.2

func (cm *DownCache) Create(ctx context.Context, post *Post) (*Post, error)

func (*DownCache) Delete added in v0.0.2

func (cm *DownCache) Delete(ctx context.Context, postType, slug string) error

func (*DownCache) Get added in v0.0.2

func (cm *DownCache) Get(ctx context.Context, postType, slug string) (*Post, error)

func (*DownCache) Search added in v0.0.2

func (cm *DownCache) Search(ctx context.Context, filter FilterOptions) ([]*Post, int, error)

func (*DownCache) SyncAll added in v0.0.2

func (cm *DownCache) SyncAll(ctx context.Context) error

func (*DownCache) Update added in v0.0.2

func (cm *DownCache) Update(ctx context.Context, oldType, oldSlug string, post *Post) error

type FilterOptions

type FilterOptions struct {
	PageNum            int              // The page number to retrieve
	PageSize           int              // The number of items per page
	SortBy             []string         // The frontmatter fields to sort by. Default is ["-featured", "-published", "name]
	FilterAuthor       string           // The authors to filter by
	FilterProperties   []KeyValueFilter // The frontmatter fields to filter by
	FilterTaxonomies   []KeyValueFilter // The taxonomies to filter by
	FilterSearch       string           // A search string to filter by. Searches the post content, title, etc.
	FilterPostType     PostType         // The type of post to filter by (e.g. PostTypeKeyArticle, PostTypeKeyPage). Default is PostTypeKeyAny.
	FilterStatus       string           // The status of the post to filter by (e.g. "published", "draft"). Default is "published".
	FilterVisibility   string           // The visibility of the post to filter by (e.g. "public", "private"). Default is "public".
	SplitPinned        bool             // Whether to split featured items from the main list
	IncludeUnpublished bool
}

FilterOptions contains the options to filter posts.

type FilterType

type FilterType string
const (
	FilterTypeAny      FilterType = "any"
	FilterTypeAuthor   FilterType = "author"
	FilterTypeTaxonomy FilterType = "taxonomy"
)

func (FilterType) String

func (ft FilterType) String() string

type FrontmatterFormat

type FrontmatterFormat string
const (
	FrontmatterTOML FrontmatterFormat = "toml"
	FrontmatterYAML FrontmatterFormat = "yaml"
)

type KeyValueFilter added in v0.0.2

type KeyValueFilter struct {
	Key   string
	Value string
}

type LocalMarkdownFS added in v0.0.2

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

LocalMarkdownFS implements MarkdownFS for the local file system

func NewLocalMarkdownFS added in v0.0.2

func NewLocalMarkdownFS(rootDir string, proc MarkdownProcessor, format FrontmatterFormat) *LocalMarkdownFS

func (*LocalMarkdownFS) Delete added in v0.0.2

func (fs *LocalMarkdownFS) Delete(_ context.Context, postType, slug string) error

func (*LocalMarkdownFS) Move added in v0.0.2

func (fs *LocalMarkdownFS) Move(_ context.Context, oldType, oldSlug, newType, newSlug string) error

func (*LocalMarkdownFS) Read added in v0.0.2

func (fs *LocalMarkdownFS) Read(_ context.Context, postType, slug string) (*Post, error)

func (*LocalMarkdownFS) Walk added in v0.0.2

func (fs *LocalMarkdownFS) Walk(ctx context.Context) (<-chan *Post, <-chan error)

func (*LocalMarkdownFS) Write added in v0.0.2

func (fs *LocalMarkdownFS) Write(_ context.Context, post *Post) error

type MarkdownFS added in v0.0.2

type MarkdownFS interface {
	Walk(ctx context.Context) (<-chan *Post, <-chan error)
	Read(ctx context.Context, postType, slug string) (*Post, error)
	Write(ctx context.Context, post *Post) error
	Delete(ctx context.Context, postType, slug string) error
	Move(ctx context.Context, oldType, oldSlug, newType, newSlug string) error
}

MarkdownFS handles file system operations for markdown files

type MarkdownProcessor added in v0.0.2

type MarkdownProcessor interface {
	Process(input []byte) (*Post, error)
	GenerateFrontmatter(meta *PostMeta, format FrontmatterFormat) (string, error)
}

MarkdownProcessor handles markdown parsing and processing

type MemoryCacheStore added in v0.0.2

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

MemoryCacheStore implements CacheStore interface using in-memory storage

func NewMemoryCacheStore added in v0.0.2

func NewMemoryCacheStore() *MemoryCacheStore

NewMemoryCacheStore creates a new MemoryCacheStore

func (*MemoryCacheStore) Clear added in v0.0.2

func (m *MemoryCacheStore) Clear(ctx context.Context) error

Clear clears all data from the post store

func (*MemoryCacheStore) Close added in v0.0.2

func (m *MemoryCacheStore) Close() error

Close closes the post store

func (*MemoryCacheStore) Create added in v0.0.2

func (m *MemoryCacheStore) Create(ctx context.Context, post *Post) (*Post, error)

Create adds a new post to the store

func (*MemoryCacheStore) Delete added in v0.0.2

func (m *MemoryCacheStore) Delete(ctx context.Context, postType, slug string) error

Delete removes a post from the store

func (*MemoryCacheStore) Get added in v0.0.2

func (m *MemoryCacheStore) Get(ctx context.Context, postType, slug string) (*Post, error)

Get retrieves a post from the store

func (*MemoryCacheStore) GetTaxonomies added in v0.0.2

func (m *MemoryCacheStore) GetTaxonomies(ctx context.Context) ([]string, error)

GetTaxonomies returns a list of taxonomies. TODO: This is inefficient and should be optimized for large datasets.

func (*MemoryCacheStore) GetTaxonomyTerms added in v0.0.2

func (m *MemoryCacheStore) GetTaxonomyTerms(ctx context.Context, taxonomy string) ([]string, error)

GetTaxonomyTerms returns a list of terms for a given taxonomy. TODO: This is inefficient and should be optimized for large datasets.

func (*MemoryCacheStore) Init added in v0.0.2

func (m *MemoryCacheStore) Init() error

Init initializes the post store

func (*MemoryCacheStore) Search added in v0.0.2

func (m *MemoryCacheStore) Search(ctx context.Context, options FilterOptions) ([]*Post, int, error)

Search searches for posts based on the provided FilterOptions

func (*MemoryCacheStore) Update added in v0.0.2

func (m *MemoryCacheStore) Update(ctx context.Context, oldType, oldSlug string, post *Post) error

Update updates an existing post in the store

type Paginator

type Paginator struct {
	TotalPages       int
	CurrentPage      int
	NextPage         int
	PrevPage         int
	PageSize         int
	HasNext          bool
	HasPrev          bool
	HasPosts         bool
	TotalPosts       int
	AllPosts         []*Post
	FeaturedPosts    []*Post
	NonFeaturedPosts []*Post
	Visible          bool // True by default, but can be set to false in the view. E.g. on the home page.
}

Paginator is a struct that holds information about pagination, such as the total number of pages, the current page, the next and previous pages, the page size, whether there are more pages, whether there are posts, the total number of posts, all posts, featured posts, non-featured posts, and whether the paginator is visible.

func NewPaginator added in v0.0.2

func NewPaginator(docs []*Post, total, currentPage, pageSize int, includeFeatured bool) Paginator

NewPaginator returns a Paginator struct with the given parameters.

type Post

type Post struct {
	ID                int64               `json:"id"`                // ID is the unique identifier for the post
	PostID            string              `json:"post_id"`           // PostID is the unique identifier for the post (post type + slug)
	Slug              string              `json:"slug"`              // Slug is the URL-friendly version of the name
	PostType          string              `json:"postType"`          // PostType is the type of post (e.g. post, page)
	Author            string              `json:"author"`            // Author is a list of author
	Content           string              `json:"content"`           // Content is raw content of the post
	HTML              string              `json:"html"`              // HTML is the HTML content of the post
	ETag              string              `json:"etag"`              // ETag is the entity tag
	EstimatedReadTime string              `json:"estimatedReadTime"` // EstimatedReadTime is the estimated reading time
	Pinned            bool                `json:"pinned"`            // Pinned is true if the post is pinned
	Photo             string              `json:"photo"`             // Photo is the URL of the featured image
	FileTimePath      string              `json:"fileTimePath"`      // FileTimePath is the file time path in the format YYYY-MM-DD for the original file path
	Name              string              `json:"name"`              // Name is the name/title of the post
	Properties        map[string]string   `json:"properties"`        // Properties is a map of additional, arbitrary key-value pairs. This can be used to store additional metadata such as extra microformat properties.
	Published         sql.NullString      `json:"published"`         // Published is the published date
	Status            string              `json:"status"`            // Status is the status of the post (should be one of draft, published, or archived)
	Subtitle          string              `json:"subtitle"`          // Subtitle is the subtitle
	Summary           string              `json:"summary"`           // Summary is the summary
	Taxonomies        map[string][]string `json:"taxonomies"`        // Taxonomies is a map of taxonomies (e.g. tags, categories)
	Visibility        string              `json:"visibility"`        // Visibility is the visibility of the post (should be one of public, private, or unlisted)
	Created           string              `json:"created"`           // Created is the creation date
	Updated           string              `json:"updated"`           // Updated is the last modified date
	// contains filtered or unexported fields
}

Post represents a Markdown post

func Deserialize

func Deserialize(data []byte) (*Post, error)

Deserialize deserializes the byte slice to a post

func MarkdownToPost

func MarkdownToPost(md goldmark.Markdown, content []byte) (*Post, error)

MarkdownToPost converts markdown content to a Post.

func (*Post) FileTimeInSlug

func (p *Post) FileTimeInSlug() string

FileTimeInSlug returns the file date

func (*Post) HasAuthor

func (p *Post) HasAuthor() bool

HasAuthor returns true if the post has author

func (*Post) HasFileTimeInSlug

func (p *Post) HasFileTimeInSlug() bool

HasFileTimeInSlug returns true if the post has a file time path. This is the date part of the original file path.

func (*Post) HasName

func (p *Post) HasName() bool

HasName returns true if the post has a non-empty name

func (*Post) HasPhoto

func (p *Post) HasPhoto() bool

HasPhoto returns true if the post has a featured image

func (*Post) HasProperties

func (p *Post) HasProperties() bool

HasProperties returns true if the post has additional/arbitrary metadata properties

func (*Post) HasPublished

func (p *Post) HasPublished() bool

HasPublished returns true if the post has a published date

func (*Post) HasSubtitle

func (p *Post) HasSubtitle() bool

HasSubtitle returns true if the post has a subtitle

func (*Post) HasSummary

func (p *Post) HasSummary() bool

HasSummary returns true if the post has a summary

func (*Post) HasTaxonomies

func (p *Post) HasTaxonomies() bool

HasTaxonomies returns true if the post has taxonomies

func (*Post) HasTaxonomy

func (p *Post) HasTaxonomy(taxonomy string) bool

HasTaxonomy returns true if the post has the specified taxonomy

func (*Post) HasUpdated

func (p *Post) HasUpdated() bool

HasUpdated returns true if the post has a last modified date

func (*Post) Meta added in v0.0.2

func (p *Post) Meta() *PostMeta

func (*Post) PublishedDate

func (p *Post) PublishedDate() string

PublishedDate returns the published date in the format Jan 2, 2006

func (*Post) PublishedTime added in v0.0.2

func (p *Post) PublishedTime() time.Time

PublishedTime returns the published date as a time.Time

func (*Post) PublishedYear

func (p *Post) PublishedYear() int

PublishedYear returns the year of the published date

func (*Post) Serialize

func (p *Post) Serialize() ([]byte, error)

Serialize serializes the post to a byte slice

func (*Post) SlugWithYear

func (p *Post) SlugWithYear() string

SlugWithYear returns the slug with the published year prepended as a directory (if it exists)

func (*Post) SlugWithYearMonth

func (p *Post) SlugWithYearMonth() string

SlugWithYearMonth returns the slug with the published year and month prepended as a directory (if it exists)

func (*Post) SlugWithYearMonthDay

func (p *Post) SlugWithYearMonthDay() string

SlugWithYearMonthDay returns the slug with the published year, month, and day prepended as a directory (if it exists)

func (*Post) SlugWithoutDate

func (p *Post) SlugWithoutDate() string

SlugWithoutDate returns the slug without a file time path (if it exists)

func (*Post) Taxonomy

func (p *Post) Taxonomy(taxonomy string) []string

Taxonomy returns the specified taxonomy

type PostMeta

type PostMeta struct {
	Author     string              `yaml:"author,omitempty" toml:"author,omitempty"`
	Pinned     bool                `yaml:"pinned,omitempty" toml:"pinned,omitempty"`
	Name       string              `yaml:"name,omitempty" toml:"name,omitempty"`
	Photo      string              `yaml:"photo,omitempty" toml:"photo,omitempty"`
	Properties map[string]string   `yaml:"properties,omitempty" toml:"properties,omitempty"`
	Published  string              `yaml:"published,omitempty" toml:"published,omitempty"`
	Status     string              `yaml:"status,omitempty" toml:"status,omitempty"`
	Subtitle   string              `yaml:"subtitle,omitempty" toml:"subtitle,omitempty"`
	Summary    string              `yaml:"summary,omitempty" toml:"summary,omitempty"`
	Taxonomies map[string][]string `yaml:"taxonomies,omitempty" toml:"taxonomies,omitempty"`
	//Updated    time.Time           `yaml:"updated,omitempty" toml:"updated,omitempty"`
	Visibility string `yaml:"visibility,omitempty" toml:"visibility,omitempty"`
}

PostMeta represents the frontmatter of a post

func (*PostMeta) Validate

func (dm *PostMeta) Validate() error

type PostType

type PostType string

PostType is a string key that represents a post type and is used to determine the directory where posts of the given type are stored.

const (
	PostTypeKeyPage     PostType = "pages"
	PostTypeKeyArticle  PostType = "articles"
	PostTypeKeyNote     PostType = "notes"
	PostTypeKeyLink     PostType = "links"
	PostTypeKeyBookmark PostType = "bookmarks"
	PostTypeKeyAny      PostType = "any"
)

func (PostType) IsAny added in v0.0.2

func (pt PostType) IsAny() bool

IsAny returns true if the PostType is PostTypeKeyAny.

func (PostType) String added in v0.0.2

func (pt PostType) String() string

String returns the string representation of the PostType.

type PostTypes added in v0.0.2

type PostTypes []PostType

PostTypes is a slice of PostType.

func DefaultPostTypes

func DefaultPostTypes() PostTypes

func (PostTypes) HasPostType added in v0.0.2

func (pts PostTypes) HasPostType(key string) bool

HasPostType returns true if the PostType is not empty.

type SlugPath

type SlugPath struct {
	Slug         string
	FileTimePath string
	FileTime     *time.Time
	PostType     PostType
}

func SlugifyPath

func SlugifyPath(rootPath, fullPath string, postType PostType) SlugPath

SlugifyPath transforms a full OS path into a slugified path. - It trims the `rootPath` from the beginning of the `fullPath` to get the relative path. - The slug is then a combination of the `postType` and the relative path. - It removes leading and trailing slashes, and ensures no leading slash remains. - It finds the extension based on the last period in the path and trims it from the path. - If the file part of a path starts with an RFC3339 date (2006-01-02), it extracts it and removes it from the path. Note, it does not include the time part. - It trims the "/index" suffix if it exists. - It replaces all path separators with browser-compatible forward slashes. - Finally, it slugifies each path part using the slug package.

The function returns a SlugPath struct with the slugified path, the file time path, the file time, and the post type.

Directories

Path Synopsis
bboltstore module
sqlitestore module

Jump to

Keyboard shortcuts

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