mg-transport-core/core/template.go
Neur0toxine 52109ee4ba
Refactoring and new features (#35)
* new error collector & improvements for errors
* update golangci-lint, microoptimizations, linter fixes
* UseTLS10 method
* remove dead code
* add 1.17 to the test matrix
* fix for docstring
* split the core package symbols into the subpackages (if feasible)
2021-12-01 15:40:23 +03:00

98 lines
2.8 KiB
Go

package core
import (
"html/template"
"io/fs"
"github.com/gin-contrib/multitemplate"
)
// Renderer wraps multitemplate.Renderer in order to make it easier to use.
type Renderer struct {
multitemplate.Renderer
TemplatesFS fs.FS
FuncMap template.FuncMap
alreadyAdded map[string]*template.Template
}
// NewRenderer is a Renderer constructor.
func NewRenderer(funcMap template.FuncMap) Renderer {
return newRendererWithMultitemplate(funcMap, multitemplate.NewRenderer())
}
// NewStaticRenderer is a Renderer constructor with multitemplate.Render.
func NewStaticRenderer(funcMap template.FuncMap) Renderer {
return newRendererWithMultitemplate(funcMap, multitemplate.New())
}
// NewDynamicRenderer is a Renderer constructor with multitemplate.DynamicRender.
func NewDynamicRenderer(funcMap template.FuncMap) Renderer {
return newRendererWithMultitemplate(funcMap, multitemplate.NewDynamic())
}
// newRendererWithMultitemplate initializes Renderer with provided multitemplate.Renderer instance.
func newRendererWithMultitemplate(funcMap template.FuncMap, renderer multitemplate.Renderer) Renderer {
return Renderer{
Renderer: renderer,
FuncMap: funcMap,
alreadyAdded: map[string]*template.Template{},
}
}
// Push is an AddFromFilesFuncs wrapper.
func (r *Renderer) Push(name string, files ...string) *template.Template {
if tpl := r.getTemplate(name); tpl != nil {
return tpl
}
if r.TemplatesFS != nil {
return r.storeTemplate(name, r.addFromFS(name, r.FuncMap, files...))
}
return r.storeTemplate(name, r.AddFromFilesFuncs(name, r.FuncMap, files...))
}
// addFromFS adds embedded template.
func (r *Renderer) addFromFS(name string, funcMap template.FuncMap, files ...string) *template.Template {
filesData := make([]string, len(files))
for i := 0; i < len(files); i++ {
data, err := fs.ReadFile(r.TemplatesFS, files[i])
if err != nil {
panic(err)
}
filesData[i] = string(data)
}
return r.AddFromStringsFuncs(name, funcMap, filesData...)
}
// storeTemplate stores built template if multitemplate.DynamicRender is used.
// Dynamic render doesn't store templates - it stores builders, that's why we can't just extract them.
// It possibly can cause data inconsistency in developer environments where return value from Renderer.Push is used.
func (r *Renderer) storeTemplate(name string, tpl *template.Template) *template.Template {
if _, ok := r.Renderer.(multitemplate.DynamicRender); ok {
r.alreadyAdded[name] = tpl
}
return tpl
}
// getTemplate returns template from render or from storage.
func (r *Renderer) getTemplate(name string) *template.Template {
if renderer, ok := r.Renderer.(multitemplate.Render); ok {
if i, ok := renderer[name]; ok {
return i
}
}
if _, ok := r.Renderer.(multitemplate.DynamicRender); ok {
if i, ok := r.alreadyAdded[name]; ok {
return i
}
}
return nil
}