diff --git a/.gitmodules b/.gitmodules
index a757998..f013eed 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,3 @@
[submodule "mustache"]
path = mustache
- url = git://github.com/mustache/spec.git
+ url = https://github.com/mustache/spec
diff --git a/README.md b/README.md
index 3a1e712..9323794 100644
--- a/README.md
+++ b/README.md
@@ -1289,7 +1289,6 @@ These handlebars options are currently NOT implemented:
- `knownHelpers` - list of helpers that are known to exist (truthy) at template execution time
- `knownHelpersOnly` - allows further optimizations based on the known helpers list
- `trackIds` - include the id names used to resolve parameters for helpers
-- `noEscape` - disables HTML escaping globally
- `strict` - templates will throw rather than silently ignore missing fields
- `assumeObjects` - removes object existence checks when traversing paths
- `preventIndent` - disables the auto-indententation of nested partials
diff --git a/eval.go b/eval.go
index f6c2ffc..6007c6c 100644
--- a/eval.go
+++ b/eval.go
@@ -42,6 +42,9 @@ type evalVisitor struct {
// used for info on panic
curNode ast.Node
+
+ // do not escape
+ noEscape bool
}
// NewEvalVisitor instanciate a new evaluation visitor with given context and initial private data frame
@@ -806,7 +809,7 @@ func (v *evalVisitor) VisitMustache(node *ast.MustacheStatement) interface{} {
// get string value
str := Str(expr)
- if !isSafe && !node.Unescaped {
+ if !v.noEscape && !isSafe && !node.Unescaped {
// escape html
str = Escape(str)
}
diff --git a/eval_test.go b/eval_test.go
index 13481c8..5df7d84 100644
--- a/eval_test.go
+++ b/eval_test.go
@@ -295,3 +295,19 @@ func TestEvalMethodReturningFunc(t *testing.T) {
t.Errorf("Failed to evaluate struct method: %s", output)
}
}
+
+func TestEvalNoEscape(t *testing.T) {
+ t.Parallel()
+
+ source := `Hello {{value}}`
+ expected := `Hello World`
+
+ ctx := map[string]string{
+ "value": "World",
+ }
+
+ output := MustRender(source, ctx, WithNoEscape(true))
+ if output != expected {
+ t.Errorf("Failed to evaluate struct method: %s", output)
+ }
+}
diff --git a/handlebars.go b/handlebars.go
index 17a8082..638265d 100644
--- a/handlebars.go
+++ b/handlebars.go
@@ -4,7 +4,7 @@ package handlebars
// Render parses a template and evaluates it with given context
//
// Note that this function call is not optimal as your template is parsed everytime you call it. You should use Parse() function instead.
-func Render(source string, ctx interface{}) (string, error) {
+func Render(source string, ctx interface{}, opts ...execOption) (string, error) {
// parse template
tpl, err := Parse(source)
if err != nil {
@@ -12,7 +12,7 @@ func Render(source string, ctx interface{}) (string, error) {
}
// renders template
- str, err := tpl.Exec(ctx)
+ str, err := tpl.Exec(ctx, opts...)
if err != nil {
return "", err
}
@@ -23,6 +23,6 @@ func Render(source string, ctx interface{}) (string, error) {
// MustRender parses a template and evaluates it with given context. It panics on error.
//
// Note that this function call is not optimal as your template is parsed everytime you call it. You should use Parse() function instead.
-func MustRender(source string, ctx interface{}) string {
- return MustParse(source).MustExec(ctx)
+func MustRender(source string, ctx interface{}, opts ...execOption) string {
+ return MustParse(source).MustExec(ctx, opts...)
}
diff --git a/template.go b/template.go
index 8b93727..566e876 100644
--- a/template.go
+++ b/template.go
@@ -190,21 +190,30 @@ func (tpl *Template) RegisterPartialTemplate(name string, template *Template) {
}
// Exec evaluates template with given context.
-func (tpl *Template) Exec(ctx interface{}) (result string, err error) {
- return tpl.ExecWith(ctx, nil)
+func (tpl *Template) Exec(ctx interface{}, opts ...execOption) (result string, err error) {
+ return tpl.ExecWith(ctx, nil, opts...)
}
// MustExec evaluates template with given context. It panics on error.
-func (tpl *Template) MustExec(ctx interface{}) string {
- result, err := tpl.Exec(ctx)
+func (tpl *Template) MustExec(ctx interface{}, opts ...execOption) string {
+ result, err := tpl.Exec(ctx, opts...)
if err != nil {
panic(err)
}
return result
}
+type execOption func(*evalVisitor)
+
+// Set noEscape option
+func WithNoEscape(noEscape bool) func(*evalVisitor) {
+ return func(option *evalVisitor) {
+ option.noEscape = noEscape
+ }
+}
+
// ExecWith evaluates template with given context and private data frame.
-func (tpl *Template) ExecWith(ctx interface{}, privData *DataFrame) (result string, err error) {
+func (tpl *Template) ExecWith(ctx interface{}, privData *DataFrame, opts ...execOption) (result string, err error) {
defer errRecover(&err)
// parses template if necessary
@@ -215,6 +224,9 @@ func (tpl *Template) ExecWith(ctx interface{}, privData *DataFrame) (result stri
// setup visitor
v := newEvalVisitor(tpl, ctx, privData)
+ for _, opt := range opts {
+ opt(v)
+ }
// visit AST
result, _ = tpl.program.Accept(v).(string)