95 lines
2.4 KiB
Go
95 lines
2.4 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
var ErrPageNotFound = fmt.Errorf("page not found")
|
|
|
|
// A Page is a single unit of content on the site.
|
|
type Page struct {
|
|
Title string
|
|
Contents []byte
|
|
}
|
|
|
|
// Index is a set of pages that exist at this level,
|
|
// as well as a set of "folders" that contain sub-indexes.
|
|
// The 'index' key in Pages is special, and will be returned
|
|
// if no key is provided.
|
|
type Index struct {
|
|
Children map[string]Index
|
|
Pages map[string]Page
|
|
}
|
|
|
|
// Page returns the requested page from the index, recursively
|
|
// key is assumed to be a `/`-separated string; Page will split on the slashes,
|
|
// descending into an index to find the page, if possible. If no match is found,
|
|
// return an empty page and `ErrPageNotFound`.
|
|
// `foo/` will return a page named `foo` in the current index, if it exists.
|
|
// Otherwise, if a child index named "foo" exists, page will attempt to return its index page.
|
|
// Page strips leading / from keys.
|
|
func (i *Index) Page(key string) (*Page, error) {
|
|
if key == "" || key == "/" {
|
|
key = "index"
|
|
}
|
|
if key[0] == '/' { // strip leading slash
|
|
key = key[1:]
|
|
}
|
|
curr, rest, found := strings.Cut(key, "/")
|
|
page, pageok := i.Pages[curr]
|
|
child, childok := i.Children[curr]
|
|
// no trailing slash and doesn't exist
|
|
if !found && !pageok {
|
|
return &Page{}, ErrPageNotFound
|
|
}
|
|
// trailing slash, exists as page
|
|
if rest == "" && pageok {
|
|
return &page, nil
|
|
}
|
|
// neither page nor child
|
|
if !childok {
|
|
return &Page{}, ErrPageNotFound
|
|
}
|
|
// recurse
|
|
return (&child).Page(rest)
|
|
}
|
|
|
|
// Save stores a page in the index, recursively,
|
|
// overwriting any that may have existed before.
|
|
// `foo/` is stored as a page named 'foo' in the current index;
|
|
// default 'index' files should be explicitly passed as such.
|
|
// The empty key or `/` are invalid and result in an error.
|
|
// Leading slashes are stripped.
|
|
func (i *Index) Save(key string, page *Page) error {
|
|
if key == "" || key == "/" {
|
|
return fmt.Errorf("invalid page key")
|
|
}
|
|
if key[0] == '/' { // strip leading slash
|
|
key = key[1:]
|
|
}
|
|
// init maps if not yet created
|
|
if i.Pages == nil {
|
|
i.Pages = map[string]Page{}
|
|
}
|
|
if i.Children == nil {
|
|
i.Children = map[string]Index{}
|
|
}
|
|
|
|
// save as page
|
|
curr, rest, _ := strings.Cut(key, "/")
|
|
if rest == "" {
|
|
i.Pages[curr] = *page
|
|
return nil
|
|
}
|
|
|
|
// recurse and save in child
|
|
children := i.Children[curr]
|
|
err := (&children).Save(rest, page)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
i.Children[curr] = children
|
|
return nil
|
|
}
|