Pass template as value
This commit is contained in:
		| @@ -26,7 +26,7 @@ import ( | ||||
| // Namespace represents a collection of templates that can include each other | ||||
| type Namespace struct { | ||||
| 	mu    sync.Mutex | ||||
| 	tmpls map[string]*Template | ||||
| 	tmpls map[string]Template | ||||
| 	vars  map[string]reflect.Value | ||||
| 	tags  map[string]Tag | ||||
| } | ||||
| @@ -34,7 +34,7 @@ type Namespace struct { | ||||
| // New returns a new template namespace | ||||
| func New() *Namespace { | ||||
| 	return &Namespace{ | ||||
| 		tmpls: map[string]*Template{}, | ||||
| 		tmpls: map[string]Template{}, | ||||
| 		vars:  map[string]reflect.Value{}, | ||||
| 		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. | ||||
| // If it finds the template, it returns the template and true. If it | ||||
| // 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() | ||||
| 	defer n.mu.Unlock() | ||||
| 	t, ok := n.tmpls[name] | ||||
|   | ||||
							
								
								
									
										32
									
								
								parse.go
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								parse.go
									
									
									
									
									
								
							| @@ -26,6 +26,7 @@ import ( | ||||
| 	"path/filepath" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"go.elara.ws/salix/ast" | ||||
| 	"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 | ||||
| // 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) | ||||
| } | ||||
|  | ||||
| // 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) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 		return Template{}, err | ||||
| 	} | ||||
|  | ||||
| 	t := &Template{ | ||||
| 		ns:   n, | ||||
| 		name: name, | ||||
| 		ast:  astVal.([]ast.Node), | ||||
| 		tags: map[string]Tag{}, | ||||
| 		vars: map[string]reflect.Value{}, | ||||
| 	t := Template{ | ||||
| 		ns:       n, | ||||
| 		name:     name, | ||||
| 		ast:      astVal.([]ast.Node), | ||||
| 		tags:     map[string]Tag{}, | ||||
| 		vars:     map[string]reflect.Value{}, | ||||
| 		macroMtx: &sync.Mutex{}, | ||||
| 	} | ||||
|  | ||||
| 	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. | ||||
| func (t *Namespace) ParseFile(path string) (*Template, error) { | ||||
| func (t *Namespace) ParseFile(path string) (Template, error) { | ||||
| 	fl, err := os.Open(path) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 		return Template{}, err | ||||
| 	} | ||||
| 	defer fl.Close() | ||||
| 	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. | ||||
| 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) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 		return Template{}, err | ||||
| 	} | ||||
| 	defer fl.Close() | ||||
| 	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. | ||||
| 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)) | ||||
| } | ||||
|  | ||||
| // 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)) | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										68
									
								
								salix.go
									
									
									
									
									
								
							
							
						
						
									
										68
									
								
								salix.go
									
									
									
									
									
								
							| @@ -63,86 +63,44 @@ type Template struct { | ||||
| 	tags map[string]Tag | ||||
| 	vars map[string]reflect.Value | ||||
|  | ||||
| 	macroMtx sync.Mutex | ||||
| 	macroMtx *sync.Mutex | ||||
| 	macros   map[string][]ast.Node | ||||
| } | ||||
|  | ||||
| // WithVarMap returns a copy of the template with its variable map set to m. | ||||
| func (t *Template) WithVarMap(m map[string]any) *Template { | ||||
| 	newTmpl := &Template{ | ||||
| 		ns:   t.ns, | ||||
| 		name: t.name, | ||||
| 		ast:  t.ast, | ||||
|  | ||||
| 		escapeHTML: t.escapeHTML, | ||||
|  | ||||
| 		tags: t.tags, | ||||
| 		vars: map[string]reflect.Value{}, | ||||
| 	} | ||||
|  | ||||
| func (t Template) WithVarMap(m map[string]any) Template { | ||||
| 	t.vars = map[string]reflect.Value{} | ||||
| 	if m != nil { | ||||
| 		for k, v := range m { | ||||
| 			newTmpl.vars[k] = reflect.ValueOf(v) | ||||
| 			t.vars[k] = reflect.ValueOf(v) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return newTmpl | ||||
| 	return t | ||||
| } | ||||
|  | ||||
| // 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 | ||||
| 	if m == nil { | ||||
| 		m = map[string]Tag{} | ||||
| 	} | ||||
|  | ||||
| 	return &Template{ | ||||
| 		ns:   t.ns, | ||||
| 		name: t.name, | ||||
| 		ast:  t.ast, | ||||
|  | ||||
| 		escapeHTML: t.escapeHTML, | ||||
|  | ||||
| 		tags: m, | ||||
| 		vars: t.vars, | ||||
| 	} | ||||
| 	t.tags = m | ||||
| 	return t | ||||
| } | ||||
|  | ||||
| // WithEscapeHTML returns a copy of the template with HTML escaping enabled or disabled. | ||||
| // The HTML escaping functionality is NOT context-aware. | ||||
| // 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 | ||||
| 	return &Template{ | ||||
| 		ns:   t.ns, | ||||
| 		name: t.name, | ||||
| 		ast:  t.ast, | ||||
|  | ||||
| 		escapeHTML: b, | ||||
|  | ||||
| 		tags: t.tags, | ||||
| 		vars: t.vars, | ||||
| 	} | ||||
| 	return t | ||||
| } | ||||
|  | ||||
| // Execute executes a parsed template and writes | ||||
| // the result to w. | ||||
| func (t *Template) Execute(w io.Writer) error { | ||||
| 	// Create a new template to give each execution | ||||
| 	// its own macros | ||||
| 	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) error { | ||||
| 	t.macros = map[string][]ast.Node{} | ||||
| 	return t.execute(w, t.ast, nil) | ||||
| } | ||||
|  | ||||
| func (t *Template) execute(w io.Writer, nodes []ast.Node, local map[string]any) error { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user