init
This commit is contained in:
commit
d7911efd06
8 changed files with 465 additions and 0 deletions
118
tplx.go
Normal file
118
tplx.go
Normal file
|
@ -0,0 +1,118 @@
|
|||
// Package tplx wraps the standard html/template library to provide a little more
|
||||
// structure and ease of use.
|
||||
package tplx
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"io/fs"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrUnknownTemplate is returned when a template is not found in the renderer.
|
||||
ErrUnknownTemplate = errors.New("template not found in renderer")
|
||||
|
||||
// ErrInvalidSpec is returned when the template renderer specification is invalid.
|
||||
ErrInvalidSpec = errors.New("template renderer spec is invalid")
|
||||
)
|
||||
|
||||
// Renderer is an interface for rendering templates.
|
||||
//
|
||||
// Render writes the output of the specified template to the provided writer. The
|
||||
// name parameter specifies the template to execute, data provides the context
|
||||
// data for the template, and funcs provides additional template functions.
|
||||
type Renderer interface {
|
||||
Render(w io.Writer, name string, data any, funcs template.FuncMap) error
|
||||
}
|
||||
|
||||
type renderer struct {
|
||||
m map[string]*template.Template
|
||||
}
|
||||
|
||||
// Spec describes the structure of all templates managed by the renderer.
|
||||
//
|
||||
// The keys of the Spec map represent top-level template names. Each key maps
|
||||
// to a slice of Meta, where each Meta defines the name, path, and functions
|
||||
// associated with a template fragment.
|
||||
type Spec map[string][]Meta
|
||||
|
||||
// Meta represents metadata for a single template fragment.
|
||||
//
|
||||
// Name specifies the name of the template fragment. Path specifies the path to
|
||||
// the template file in the file system. Funcs provides template-specific
|
||||
// functions.
|
||||
type Meta struct {
|
||||
Name string
|
||||
Path string
|
||||
Funcs template.FuncMap
|
||||
}
|
||||
|
||||
// NewRenderer creates a new Renderer instance from a file system, specification,
|
||||
// and global function map.
|
||||
//
|
||||
// The fsys parameter specifies the file system from which template files are
|
||||
// loaded. The spec parameter defines the structure of the templates, mapping
|
||||
// top-level template names to their fragments. The funcs parameter provides
|
||||
// global template functions.
|
||||
//
|
||||
// Returns a Renderer instance or an error if the templates cannot be initialized
|
||||
// according to the specification.
|
||||
func NewRenderer(fsys fs.FS, spec Spec, funcs template.FuncMap) (Renderer, error) {
|
||||
r := renderer{
|
||||
m: make(map[string]*template.Template, len(spec)),
|
||||
}
|
||||
|
||||
for name, pairs := range spec {
|
||||
inc := false
|
||||
|
||||
t := template.New(name).Funcs(funcs)
|
||||
|
||||
for _, pair := range pairs {
|
||||
if pair.Name == name {
|
||||
inc = true
|
||||
}
|
||||
|
||||
text, err := fs.ReadFile(fsys, pair.Path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to read template file: %w", err)
|
||||
}
|
||||
|
||||
t = t.New(pair.Name).Funcs(pair.Funcs)
|
||||
|
||||
t, err = t.Parse(string(text))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
if !inc {
|
||||
return nil, ErrInvalidSpec
|
||||
}
|
||||
|
||||
r.m[name] = t
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// Render writes the rendered output of a named template to the provided writer.
|
||||
//
|
||||
// The wr parameter specifies the writer where the rendered template output will
|
||||
// be written. The name parameter specifies the name of the template to render
|
||||
// The data parameter provides the context data for rendering, and the funcs
|
||||
// parameter provides additional template functions.
|
||||
//
|
||||
// Returns an error if the template cannot be rendered or does not exist.
|
||||
func (r renderer) Render(wr io.Writer, name string, data any, funcs template.FuncMap) error {
|
||||
t, ok := r.m[name]
|
||||
if !ok {
|
||||
return ErrUnknownTemplate
|
||||
}
|
||||
err := t.ExecuteTemplate(wr, name, data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot render template: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue