downcache

package module
v0.0.1 Latest Latest
Warning

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

Go to latest
Published: Aug 27, 2024 License: Apache-2.0 Imports: 26 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 (
	ErrPostExists         = errors.New("post already exists")
	ErrPostNotFound       = errors.New("post not found")
	ErrInvalidPostType    = errors.New("invalid post type")
	ErrInvalidPostSlug    = errors.New("invalid post slug")
	ErrInvalidPostMeta    = errors.New("invalid post metadata")
	ErrMissingPostContent = errors.New("missing post content")
)

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 PostID

func PostID(postType, slug string) string

PostID 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 Database

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

func NewDatabase

func NewDatabase(dbPath string) (*Database, error)

func (*Database) Close

func (d *Database) Close() error

type DownCache

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

DownCache is the main struct for interacting with the DownCache library. It provides methods for indexing, querying, and managing markdown posts.

func NewDownCache

func NewDownCache(opts Options) (*DownCache, error)

NewDownCache creates a new DownCache instance with the provided options.

func (*DownCache) Close

func (dg *DownCache) Close() error

Close closes the DownCache instance by closing the bolt and bleve indexes.

func (*DownCache) CreatePost

func (dg *DownCache) CreatePost(postType, path, content string, meta *PostMeta) (string, error)

CreatePost creates a new post on the filesystem and indexes it. If the post already exists, an error will be returned.

func (*DownCache) DeIndexPost

func (dg *DownCache) DeIndexPost(pathID string) error

DeIndexPost removes a post from the indexes.

func (*DownCache) DeletePost

func (dg *DownCache) DeletePost(postType, path string) error

DeletePost deletes a post from the filesystem and deindexes it. If the post does not exist, an error will be returned.

func (*DownCache) GetPost

func (dg *DownCache) GetPost(pathID string) (*Post, error)

GetPost retrieves a post by its Path PostID. If the post does not exist, an error will be returned. The Path PostID should be the post's type (e.g. page, post) plus the post's slug, without the file extension. For example, a post with the path "post/my-first-post.md" would have a Path PostID of "post/my-first-post".

func (*DownCache) GetPosts

func (dg *DownCache) GetPosts(filter FilterOptions) (Paginator, error)

GetPosts retrieves a list of posts based on the provided filter options.

func (*DownCache) GetTaxonomyTerms

func (dg *DownCache) GetTaxonomyTerms(taxonomy string) ([]string, error)

GetTaxonomyTerms returns a list of terms for a given taxonomy.

func (*DownCache) IndexPost

func (dg *DownCache) IndexPost(doc *Post) error

IndexPost indexes an individual post in the bolt and bleve indexes.

func (*DownCache) IndexPostType

func (dg *DownCache) IndexPostType(postType PostType) (int, error)

IndexPostType indexes all posts of a given type.

func (*DownCache) Paginator

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

Paginator returns a Paginator struct with the given parameters.

func (*DownCache) Reindex

func (dg *DownCache) Reindex() (map[string]int, error)

Reindex re-indexes all markdown files in the MarkdownDir directory.

func (*DownCache) SetFrontmatterFormat

func (dg *DownCache) SetFrontmatterFormat(format FrontmatterFormat)

SetFrontmatterFormat sets the format used for frontmatter in markdown files.

func (*DownCache) SetPostType

func (dg *DownCache) SetPostType(typeKey PostTypeKey, postType PostType) error

SetPostType sets a PostType for a given PostTypeKey.

func (*DownCache) UpdatePost

func (dg *DownCache) UpdatePost(postType, path, content string, meta *PostMeta) (string, error)

UpdatePost updates an existing post on the filesystem and indexes it. If the post does not exist, an error will be returned.

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]
	FilterType         FilterType  // The type of filter to apply (author, article, taxonomy)
	FilterKey          string      // The key to filter by (e.g. "categories", "tags"). Only used for taxonomy filters currently.
	FilterTerm         string      // The term to filter by (e.g. "cat3", "tag3", "author1"). Used with FilterTypeAuthor and FilterTypeTaxonomy.
	FilterSearch       string      // A search string to filter by. Searches the post content, title, etc.
	FilterPostType     PostTypeKey // 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".
	SplitFeatured      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 MarkdownParserFunc

type MarkdownParserFunc func(input []byte) (*Post, error)

func DefaultMarkdownParser

func DefaultMarkdownParser() MarkdownParserFunc

DefaultMarkdownParser returns a MarkdownParserFunc that uses the default goldmark parser with the following extensions: - GFM - Typographer - Footnote - Frontmatter It also enables the following parser options: - AutoHeadingID - Attribute

type Options

type Options struct {
	Authors           map[string]Author  // Authors is a map of author IDs to Author structs.
	ClearIndexes      bool               // ClearIndexes will remove existing indexes before reindexing.
	DataDir           string             // DataDir is the directory where DownCache will store its indexes.
	FrontMatterFormat FrontmatterFormat  // FrontMatterFormat is the format used for frontmatter in markdown files. Default is TOML.
	Logger            *slog.Logger       // Logger is the logger used by DownCache. Default is a debug logger to stderr.
	MarkdownDir       string             // MarkdownDir is the directory where markdown files are stored.
	MarkdownParser    MarkdownParserFunc // MarkdownParser is the function used to parse markdown files. A default parser is used if not provided.
	Reindex           bool               // Reindex will reindex all markdown files when DownCache is initialized.
	Taxonomies        map[string]string  // Taxonomies is a map of taxonomy plural names to their singular names.
}

Options is a struct for configuring a new DownCache instance.

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.

type Post

type Post struct {
	ID                string              `json:"id"`                // ID is the unique identifier for the post
	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 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
	Updated           time.Time           `json:"updated"`           // Updated is the last modified date
	Name              string              `json:"name"`              // Name is the name/title of the post
	Properties        map[string]any      `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         time.Time           `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)
	// 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 ReadFile

func ReadFile(markdownParser MarkdownParserFunc, rootPath, path string, postType PostType) (*Post, error)

ReadFile reads a markdown file from the filesystem and converts it to a Post.

func (*Post) FileTimeInSlug

func (d *Post) FileTimeInSlug() string

FileTimeInSlug returns the file date

func (*Post) HasAuthor

func (d *Post) HasAuthor() bool

HasAuthor returns true if the post has author

func (*Post) HasFileTimeInSlug

func (d *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 (d *Post) HasName() bool

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

func (*Post) HasPhoto

func (d *Post) HasPhoto() bool

HasPhoto returns true if the post has a featured image

func (*Post) HasProperties

func (d *Post) HasProperties() bool

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

func (*Post) HasPublished

func (d *Post) HasPublished() bool

HasPublished returns true if the post has a published date

func (*Post) HasSubtitle

func (d *Post) HasSubtitle() bool

HasSubtitle returns true if the post has a subtitle

func (*Post) HasSummary

func (d *Post) HasSummary() bool

HasSummary returns true if the post has a summary

func (*Post) HasTaxonomies

func (d *Post) HasTaxonomies() bool

HasTaxonomies returns true if the post has taxonomies

func (*Post) HasTaxonomy

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

HasTaxonomy returns true if the post has the specified taxonomy

func (*Post) HasUpdated

func (d *Post) HasUpdated() bool

HasUpdated returns true if the post has a last modified date

func (*Post) PublishedDate

func (d *Post) PublishedDate() string

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

func (*Post) PublishedYear

func (d *Post) PublishedYear() int

PublishedYear returns the year of the published date

func (*Post) Serialize

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

Serialize serializes the post to a byte slice

func (*Post) SlugWithYear

func (d *Post) SlugWithYear() string

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

func (*Post) SlugWithYearMonth

func (d *Post) SlugWithYearMonth() string

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

func (*Post) SlugWithYearMonthDay

func (d *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 (d *Post) SlugWithoutDate() string

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

func (*Post) Taxonomy

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

Taxonomy returns the specified taxonomy

type PostMeta

type PostMeta struct {
	Authors    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]any      `yaml:"properties,omitempty" toml:"properties,omitempty"`
	Published  time.Time           `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 PostStore

type PostStore interface {
	// Init initializes the post store, such as creating the necessary tables or indexes.
	Init() error
	// Create creates a new post.
	Create(post *Post) (*Post, error)
	// Update updates an existing post.
	Update(post *Post) error
	// Delete deletes a post.
	Delete(post *Post) error
	// GetBySlug retrieves a post by its slug.
	GetBySlug(slug string) (*Post, error)
	// Search searches for posts based on the provided filter options.
	Search(opts FilterOptions) ([]*Post, error)
	// Close closes the post store.
	Close() error
}

type PostType

type PostType struct {
	TypeKey          PostTypeKey               `json:"type"`
	DirPattern       string                    `json:"dirPattern"`
	FrontmatterCheck func(map[string]any) bool `json:"-"`
}

PostType defines a rule for determining the type of post based on its path and frontmatter.

type PostTypeKey

type PostTypeKey string

PostTypeKey is a string key that represents a post type.

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

func (PostTypeKey) String

func (ptk PostTypeKey) String() string

String returns the string representation of the PostTypeKey.

type PostTypesMap

type PostTypesMap map[PostTypeKey]PostType

PostTypesMap is a map of PostTypeKey to PostType.

func DefaultPostTypes

func DefaultPostTypes() PostTypesMap

DefaultPostTypes returns the default post types for a DownCache instance. The default rules are: - Posts are in the "articles/" directory and have a "date" frontmatter key. - Pages are in the "pages/" directory and have no specific frontmatter requirements.

func (PostTypesMap) IsValidTypeKey

func (ptm PostTypesMap) IsValidTypeKey(key string) bool

IsValidTypeKey returns true if the given key is a valid PostTypeKey in the PostTypesMap.

func (PostTypesMap) PostTypeFromPath

func (ptm PostTypesMap) PostTypeFromPath(filePath string) PostType

PostTypeFromPath returns the PostType for the given file path. If no rule matches, an empty PostType is returned.

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