alpha/model.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 turned into the "index" key.
// Leading slashes are stripped.
func (i *Index) Save(key string, page *Page) error {
if key == "" || key == "/" {
key = "index"
}
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
}