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)