You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

127 lines
2.5 KiB
Go

package tmpl
import (
"html/template"
"io/fs"
"path/filepath"
"strings"
txttmpl "text/template"
"unicode/utf8"
)
// Templates for getting a template tree
type Templates struct {
Suffix string
Root string
Funcs map[string]interface{}
fs.FS
}
// HTML returns templates based on a filesystem
func (t Templates) HTML(name string) (*template.Template, error) {
var ret *template.Template
parseTemplates := func(name string, body []byte) error {
var tmpl *template.Template
if ret == nil {
tmpl = template.New(name)
if t.Funcs != nil {
tmpl = tmpl.Funcs(template.FuncMap(t.Funcs))
}
} else {
tmpl = ret.New(name)
}
tmpl, err := tmpl.Parse(string(body))
if err != nil {
return err
}
ret = tmpl
return nil
}
if err := t.walk(parseTemplates); err != nil {
return nil, err
}
if t := ret.Lookup(name); t != nil {
return t, nil
}
return ret, nil
}
// Text returns templates based on a filesystem
func (t Templates) Text(name string) (*txttmpl.Template, error) {
var ret *txttmpl.Template
parseTemplates := func(name string, body []byte) error {
var tmpl *txttmpl.Template
if ret == nil {
tmpl = txttmpl.New(name)
if t.Funcs != nil {
tmpl = tmpl.Funcs(txttmpl.FuncMap(t.Funcs))
}
} else {
tmpl = ret.New(name)
}
tmpl, err := tmpl.Parse(string(body))
if err != nil {
return err
}
ret = tmpl
return nil
}
if err := t.walk(parseTemplates); err != nil {
return nil, err
}
if t := ret.Lookup(name); t != nil {
return t, nil
}
return ret, nil
}
// List returns a list of files
func (t Templates) List() ([]string, error) {
ret := []string{}
err := t.walk(func(name string, _ []byte) error {
ret = append(ret, name)
return nil
})
if err != nil {
return nil, err
}
return ret, nil
}
func (t Templates) walk(handle func(string, []byte) error) error {
return fs.WalkDir(t.FS, t.getRoot(), func(path string, d fs.DirEntry, er error) (err error) {
if er != nil {
return er
}
if d.IsDir() {
return nil
}
if !strings.HasSuffix(path, t.Suffix) {
return nil
}
body, err := fs.ReadFile(t, path)
if err != nil {
return err
}
if !utf8.Valid(body) {
return nil
}
return handle(t.trim(path), body)
})
}
func (t Templates) getRoot() string {
if t.Root == "" {
return "."
}
return filepath.Clean(t.Root)
}
func (t Templates) trim(path string) string {
cleaned := strings.TrimPrefix(filepath.Clean(path), filepath.Clean(t.Root))
cleaned = strings.TrimPrefix(cleaned, "/")
cleaned = strings.TrimSuffix(cleaned, t.Suffix)
return strings.TrimSuffix(cleaned, ".")
}