1
0
mirror of https://github.com/danog/liquid.git synced 2024-12-02 17:28:38 +01:00
liquid/render/render.go

98 lines
2.5 KiB
Go
Raw Normal View History

2017-07-10 05:15:05 +02:00
// Package render renders a template parse tree.
//
// Except where noted in the documentation for the liquid package, even public symbols
// in this package are intended to be public only to other subpackages within this
// repo, and are not guaranteed stable even across subminor version number increments.
2017-07-04 17:03:18 +02:00
package render
2017-06-25 17:23:20 +02:00
2017-06-25 23:00:00 +02:00
import (
"fmt"
"io"
2017-06-29 19:41:26 +02:00
"reflect"
2017-07-03 18:00:43 +02:00
2017-07-05 17:35:07 +02:00
"github.com/osteele/liquid/evaluator"
2017-06-25 23:00:00 +02:00
)
2017-06-25 17:23:20 +02:00
// Render renders the render tree.
2017-07-10 17:49:14 +02:00
func Render(node Node, w io.Writer, vars map[string]interface{}, c Config) Error {
2017-07-07 11:41:37 +02:00
return renderNode(node, w, newNodeContext(vars, c))
2017-06-25 17:23:20 +02:00
}
2017-07-10 17:49:14 +02:00
func renderNode(node Node, w io.Writer, ctx nodeContext) Error { // nolint: gocyclo
switch n := node.(type) {
case *BlockNode:
2017-07-04 22:48:38 +02:00
cd, ok := ctx.config.findBlockDef(n.Name)
if !ok || cd.parser == nil {
// this should have been detected during compilation; it's an implementation error if it happens here
2017-07-10 17:49:14 +02:00
panic(fmt.Errorf("unknown tag: %s", n.Name))
}
renderer := n.renderer
if renderer == nil {
2017-07-10 17:49:14 +02:00
panic(fmt.Errorf("unset renderer for %v", n))
}
2017-07-10 17:49:14 +02:00
err := renderer(w, rendererContext{ctx, nil, n})
return wrapRenderError(err, n)
case *RawNode:
for _, s := range n.slices {
_, err := w.Write([]byte(s))
if err != nil {
2017-07-10 17:49:14 +02:00
return wrapRenderError(err, n)
}
}
case *ObjectNode:
value, err := ctx.Evaluate(n.expr)
2017-06-27 23:40:15 +02:00
if err != nil {
2017-07-10 17:49:14 +02:00
return wrapRenderError(err, n)
2017-06-27 23:40:15 +02:00
}
2017-07-10 17:49:14 +02:00
return wrapRenderError(writeObject(value, w), n)
case *SeqNode:
for _, c := range n.Children {
if err := renderNode(c, w, ctx); err != nil {
return err
}
}
2017-07-07 15:32:24 +02:00
case *TagNode:
2017-07-10 17:49:14 +02:00
return wrapRenderError(n.renderer(w, rendererContext{ctx, n, nil}), n)
case *TextNode:
_, err := w.Write([]byte(n.Source))
2017-07-10 17:49:14 +02:00
return wrapRenderError(err, n)
default:
2017-07-10 17:49:14 +02:00
panic(fmt.Errorf("unknown node type %T", node))
2017-06-27 23:40:15 +02:00
}
return nil
}
2017-06-30 20:51:21 +02:00
// writeObject writes a value used in an object node
func writeObject(value interface{}, w io.Writer) error {
2017-07-05 17:35:07 +02:00
value = evaluator.ToLiquid(value)
2017-06-29 19:41:26 +02:00
if value == nil {
2017-06-27 23:29:50 +02:00
return nil
}
2017-06-29 19:41:26 +02:00
rt := reflect.ValueOf(value)
switch rt.Kind() {
case reflect.Array, reflect.Slice:
for i := 0; i < rt.Len(); i++ {
item := rt.Index(i)
if item.IsValid() {
2017-06-30 20:51:21 +02:00
if err := writeObject(item.Interface(), w); err != nil {
2017-06-29 19:41:26 +02:00
return err
}
}
}
return nil
default:
_, err := w.Write([]byte(fmt.Sprint(value)))
return err
}
2017-06-25 17:23:20 +02:00
}
// RenderASTSequence renders a sequence of nodes.
2017-07-10 17:49:14 +02:00
func (c nodeContext) RenderSequence(w io.Writer, seq []Node) Error {
for _, n := range seq {
if err := renderNode(n, w, c); err != nil {
return err
}
}
return nil
}