Pass template as value
This commit is contained in:
parent
69e515326f
commit
2a87e4781c
@ -26,7 +26,7 @@ import (
|
|||||||
// Namespace represents a collection of templates that can include each other
|
// Namespace represents a collection of templates that can include each other
|
||||||
type Namespace struct {
|
type Namespace struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
tmpls map[string]*Template
|
tmpls map[string]Template
|
||||||
vars map[string]reflect.Value
|
vars map[string]reflect.Value
|
||||||
tags map[string]Tag
|
tags map[string]Tag
|
||||||
}
|
}
|
||||||
@ -34,7 +34,7 @@ type Namespace struct {
|
|||||||
// New returns a new template namespace
|
// New returns a new template namespace
|
||||||
func New() *Namespace {
|
func New() *Namespace {
|
||||||
return &Namespace{
|
return &Namespace{
|
||||||
tmpls: map[string]*Template{},
|
tmpls: map[string]Template{},
|
||||||
vars: map[string]reflect.Value{},
|
vars: map[string]reflect.Value{},
|
||||||
tags: map[string]Tag{},
|
tags: map[string]Tag{},
|
||||||
}
|
}
|
||||||
@ -72,7 +72,7 @@ func (n *Namespace) WithTagMap(m map[string]Tag) *Namespace {
|
|||||||
// GetTemplate tries to get a template from the namespace's template map.
|
// GetTemplate tries to get a template from the namespace's template map.
|
||||||
// If it finds the template, it returns the template and true. If it
|
// If it finds the template, it returns the template and true. If it
|
||||||
// doesn't find it, it returns nil and false.
|
// doesn't find it, it returns nil and false.
|
||||||
func (n *Namespace) GetTemplate(name string) (*Template, bool) {
|
func (n *Namespace) GetTemplate(name string) (Template, bool) {
|
||||||
n.mu.Lock()
|
n.mu.Lock()
|
||||||
defer n.mu.Unlock()
|
defer n.mu.Unlock()
|
||||||
t, ok := n.tmpls[name]
|
t, ok := n.tmpls[name]
|
||||||
|
32
parse.go
32
parse.go
@ -26,6 +26,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"go.elara.ws/salix/ast"
|
"go.elara.ws/salix/ast"
|
||||||
"go.elara.ws/salix/parser"
|
"go.elara.ws/salix/parser"
|
||||||
@ -39,23 +40,24 @@ type NamedReader interface {
|
|||||||
|
|
||||||
// Parse parses a salix template from a NamedReader, which is an io.Reader
|
// Parse parses a salix template from a NamedReader, which is an io.Reader
|
||||||
// with a Name method that returns a string. os.File implements NamedReader.
|
// with a Name method that returns a string. os.File implements NamedReader.
|
||||||
func (n *Namespace) Parse(r NamedReader) (*Template, error) {
|
func (n *Namespace) Parse(r NamedReader) (Template, error) {
|
||||||
return n.ParseWithName(r.Name(), r)
|
return n.ParseWithName(r.Name(), r)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseWithFilename parses a salix template from r, using the given name.
|
// ParseWithFilename parses a salix template from r, using the given name.
|
||||||
func (n *Namespace) ParseWithName(name string, r io.Reader) (*Template, error) {
|
func (n *Namespace) ParseWithName(name string, r io.Reader) (Template, error) {
|
||||||
astVal, err := parser.ParseReader(name, r)
|
astVal, err := parser.ParseReader(name, r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return Template{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
t := &Template{
|
t := Template{
|
||||||
ns: n,
|
ns: n,
|
||||||
name: name,
|
name: name,
|
||||||
ast: astVal.([]ast.Node),
|
ast: astVal.([]ast.Node),
|
||||||
tags: map[string]Tag{},
|
tags: map[string]Tag{},
|
||||||
vars: map[string]reflect.Value{},
|
vars: map[string]reflect.Value{},
|
||||||
|
macroMtx: &sync.Mutex{},
|
||||||
}
|
}
|
||||||
|
|
||||||
performWhitespaceMutations(t.ast)
|
performWhitespaceMutations(t.ast)
|
||||||
@ -67,10 +69,10 @@ func (n *Namespace) ParseWithName(name string, r io.Reader) (*Template, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ParseFile parses the file at path as a salix template. It uses the path as the name.
|
// ParseFile parses the file at path as a salix template. It uses the path as the name.
|
||||||
func (t *Namespace) ParseFile(path string) (*Template, error) {
|
func (t *Namespace) ParseFile(path string) (Template, error) {
|
||||||
fl, err := os.Open(path)
|
fl, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return Template{}, err
|
||||||
}
|
}
|
||||||
defer fl.Close()
|
defer fl.Close()
|
||||||
return t.Parse(fl)
|
return t.Parse(fl)
|
||||||
@ -95,10 +97,10 @@ func (t *Namespace) ParseGlob(glob string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ParseFile parses a file at the given path in a filesystem. It uses the path as the name.
|
// ParseFile parses a file at the given path in a filesystem. It uses the path as the name.
|
||||||
func (t *Namespace) ParseFS(fsys fs.FS, path string) (*Template, error) {
|
func (t *Namespace) ParseFS(fsys fs.FS, path string) (Template, error) {
|
||||||
fl, err := fsys.Open(path)
|
fl, err := fsys.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return Template{}, err
|
||||||
}
|
}
|
||||||
defer fl.Close()
|
defer fl.Close()
|
||||||
return t.ParseWithName(path, fl)
|
return t.ParseWithName(path, fl)
|
||||||
@ -123,12 +125,12 @@ func (t *Namespace) ParseFSGlob(fsys fs.FS, glob string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ParseString parses a string using the given filename.
|
// ParseString parses a string using the given filename.
|
||||||
func (t *Namespace) ParseString(filename, tmpl string) (*Template, error) {
|
func (t *Namespace) ParseString(filename, tmpl string) (Template, error) {
|
||||||
return t.ParseWithName(filename, strings.NewReader(tmpl))
|
return t.ParseWithName(filename, strings.NewReader(tmpl))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseString parses bytes using the given filename.
|
// ParseString parses bytes using the given filename.
|
||||||
func (t *Namespace) ParseBytes(filename string, tmpl []byte) (*Template, error) {
|
func (t *Namespace) ParseBytes(filename string, tmpl []byte) (Template, error) {
|
||||||
return t.ParseWithName(filename, bytes.NewReader(tmpl))
|
return t.ParseWithName(filename, bytes.NewReader(tmpl))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
68
salix.go
68
salix.go
@ -63,86 +63,44 @@ type Template struct {
|
|||||||
tags map[string]Tag
|
tags map[string]Tag
|
||||||
vars map[string]reflect.Value
|
vars map[string]reflect.Value
|
||||||
|
|
||||||
macroMtx sync.Mutex
|
macroMtx *sync.Mutex
|
||||||
macros map[string][]ast.Node
|
macros map[string][]ast.Node
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithVarMap returns a copy of the template with its variable map set to m.
|
// WithVarMap returns a copy of the template with its variable map set to m.
|
||||||
func (t *Template) WithVarMap(m map[string]any) *Template {
|
func (t Template) WithVarMap(m map[string]any) Template {
|
||||||
newTmpl := &Template{
|
t.vars = map[string]reflect.Value{}
|
||||||
ns: t.ns,
|
|
||||||
name: t.name,
|
|
||||||
ast: t.ast,
|
|
||||||
|
|
||||||
escapeHTML: t.escapeHTML,
|
|
||||||
|
|
||||||
tags: t.tags,
|
|
||||||
vars: map[string]reflect.Value{},
|
|
||||||
}
|
|
||||||
|
|
||||||
if m != nil {
|
if m != nil {
|
||||||
for k, v := range m {
|
for k, v := range m {
|
||||||
newTmpl.vars[k] = reflect.ValueOf(v)
|
t.vars[k] = reflect.ValueOf(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return t
|
||||||
return newTmpl
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithTagMap returns a copy of the template with its tag map set to m.
|
// WithTagMap returns a copy of the template with its tag map set to m.
|
||||||
func (t *Template) WithTagMap(m map[string]Tag) *Template {
|
func (t Template) WithTagMap(m map[string]Tag) Template {
|
||||||
// Make sure the tag map is never nil to avoid panics
|
// Make sure the tag map is never nil to avoid panics
|
||||||
if m == nil {
|
if m == nil {
|
||||||
m = map[string]Tag{}
|
m = map[string]Tag{}
|
||||||
}
|
}
|
||||||
|
t.tags = m
|
||||||
return &Template{
|
return t
|
||||||
ns: t.ns,
|
|
||||||
name: t.name,
|
|
||||||
ast: t.ast,
|
|
||||||
|
|
||||||
escapeHTML: t.escapeHTML,
|
|
||||||
|
|
||||||
tags: m,
|
|
||||||
vars: t.vars,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithEscapeHTML returns a copy of the template with HTML escaping enabled or disabled.
|
// WithEscapeHTML returns a copy of the template with HTML escaping enabled or disabled.
|
||||||
// The HTML escaping functionality is NOT context-aware.
|
// The HTML escaping functionality is NOT context-aware.
|
||||||
// Using the HTML type allows you to get around the escaping if needed.
|
// Using the HTML type allows you to get around the escaping if needed.
|
||||||
func (t *Template) WithEscapeHTML(b bool) *Template {
|
func (t Template) WithEscapeHTML(b bool) Template {
|
||||||
t.escapeHTML = true
|
t.escapeHTML = true
|
||||||
return &Template{
|
return t
|
||||||
ns: t.ns,
|
|
||||||
name: t.name,
|
|
||||||
ast: t.ast,
|
|
||||||
|
|
||||||
escapeHTML: b,
|
|
||||||
|
|
||||||
tags: t.tags,
|
|
||||||
vars: t.vars,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute executes a parsed template and writes
|
// Execute executes a parsed template and writes
|
||||||
// the result to w.
|
// the result to w.
|
||||||
func (t *Template) Execute(w io.Writer) error {
|
func (t Template) Execute(w io.Writer) error {
|
||||||
// Create a new template to give each execution
|
t.macros = map[string][]ast.Node{}
|
||||||
// its own macros
|
return t.execute(w, t.ast, nil)
|
||||||
tmpl := &Template{
|
|
||||||
ns: t.ns,
|
|
||||||
name: t.name,
|
|
||||||
ast: t.ast,
|
|
||||||
|
|
||||||
escapeHTML: t.escapeHTML,
|
|
||||||
|
|
||||||
tags: t.tags,
|
|
||||||
vars: t.vars,
|
|
||||||
macros: map[string][]ast.Node{},
|
|
||||||
}
|
|
||||||
|
|
||||||
return tmpl.execute(w, t.ast, nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Template) execute(w io.Writer, nodes []ast.Node, local map[string]any) error {
|
func (t *Template) execute(w io.Writer, nodes []ast.Node, local map[string]any) error {
|
||||||
|
Loading…
Reference in New Issue
Block a user