tl/loader.go
2025-07-01 13:21:08 +05:00

102 lines
2.3 KiB
Go

package tl
import (
"html/template"
"io/fs"
"os"
"path"
"path/filepath"
"strings"
)
// Template collection.
type Collection struct {
// Path to the directory with templates.
RootDir string
// By default, template name is it's path relative to [RootDir].
// This prefix will be prepended to a template name: Prefix + "/" + RelativePath.
// You can leave it empty, then it will be ignored.
Prefix string
}
// Advanced options.
type Options struct {
// Files from shared collections will be available in every main template.
SharedCollections []Collection
}
// Load templates from specified directories with default options.
// Files from the main collection will be added to the returned map.
func Load(mainCollection Collection) (map[string]*template.Template, error) {
return LoadWithOptions(mainCollection, Options{})
}
// Load templates from specified directories.
// Files from [mainTemplates] collection will be added to the returned map.
func LoadWithOptions(
mainCollection Collection,
options Options,
) (map[string]*template.Template, error) {
sharedTemplate := template.New("")
for _, stp := range options.SharedCollections {
files, err := getFiles(stp.RootDir, stp.Prefix)
if err != nil {
return nil, err
}
for name, contents := range files {
sharedTemplate, err = sharedTemplate.New(name).Parse(contents)
if err != nil {
return nil, err
}
}
}
templateFiles, err := getFiles(mainCollection.RootDir, mainCollection.Prefix)
if err != nil {
return nil, err
}
res := make(map[string]*template.Template)
for name, contents := range templateFiles {
clone, err := sharedTemplate.Clone()
if err != nil {
return nil, err
}
res[name], err = clone.New(name).Parse(contents)
if err != nil {
return nil, err
}
}
return res, nil
}
func getFiles(root string, keyPrefix string) (map[string]string, error) {
res := make(map[string]string)
if !strings.HasSuffix(root, "/") {
root += "/"
}
err := filepath.WalkDir(root, func(entrypath string, d fs.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() {
return nil
}
shortPath := path.Join(keyPrefix, strings.TrimPrefix(entrypath, root))
contents, err := os.ReadFile(entrypath)
if err != nil {
return err
}
res[shortPath] = string(contents)
return nil
})
return res, err
}