aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <[email protected]>2022-10-24 15:28:03 +0200
committerBjørn Erik Pedersen <[email protected]>2022-10-24 17:21:42 +0200
commit09e10110a35cd9f0df6227a66186fd1df0c93414 (patch)
treefead128e70e74ee652f9ba7e8c5c698d8301f834
parent2ef60dbd2d9a04a8a1bb4fcdee11a7a32d2416f8 (diff)
downloadhugo-09e10110a35cd9f0df6227a66186fd1df0c93414.tar.gz
hugo-09e10110a35cd9f0df6227a66186fd1df0c93414.zip
tpl/encoding: Add noHTMLEscape option to jsonify
-rw-r--r--docs/content/en/functions/jsonify.md11
-rw-r--r--tpl/encoding/encoding.go42
-rw-r--r--tpl/encoding/encoding_test.go9
3 files changed, 51 insertions, 11 deletions
diff --git a/docs/content/en/functions/jsonify.md b/docs/content/en/functions/jsonify.md
index 28b90534c..3aa38c8c4 100644
--- a/docs/content/en/functions/jsonify.md
+++ b/docs/content/en/functions/jsonify.md
@@ -32,6 +32,17 @@ more copies of *indent* according to the indentation nesting.
{{ dict "title" .Title "content" .Plain | jsonify (dict "prefix" " " "indent" " ") }}
```
+## Jsonify options
+
+indent ("")
+: Indendation to use.
+
+prefix ("")
+: Indentation prefix.
+
+noHTMLEscape (false)
+: Disable escaping of problematic HTML characters inside JSON quoted strings. The default behavior is to escape &, <, and > to \u0026, \u003c, and \u003e to avoid certain safety problems that can arise when embedding JSON in HTML.
+
See also the `.PlainWords`, `.Plain`, and `.RawContent` [page variables][pagevars].
[pagevars]: /variables/page/
diff --git a/tpl/encoding/encoding.go b/tpl/encoding/encoding.go
index 272503e0c..0510f86e2 100644
--- a/tpl/encoding/encoding.go
+++ b/tpl/encoding/encoding.go
@@ -20,7 +20,10 @@ import (
"errors"
"html/template"
+ bp "github.com/gohugoio/hugo/bufferpool"
+
"github.com/gohugoio/hugo/common/maps"
+ "github.com/mitchellh/mapstructure"
"github.com/spf13/cast"
)
@@ -60,24 +63,27 @@ func (ns *Namespace) Base64Encode(content any) (string, error) {
// to the indentation nesting.
func (ns *Namespace) Jsonify(args ...any) (template.HTML, error) {
var (
- b []byte
- err error
+ b []byte
+ err error
+ obj any
+ opts jsonifyOpts
)
switch len(args) {
case 0:
return "", nil
case 1:
- b, err = json.Marshal(args[0])
+ obj = args[0]
case 2:
- var opts map[string]string
-
- opts, err = maps.ToStringMapStringE(args[0])
+ var m map[string]any
+ m, err = maps.ToStringMapE(args[0])
if err != nil {
break
}
-
- b, err = json.MarshalIndent(args[1], opts["prefix"], opts["indent"])
+ if err = mapstructure.WeakDecode(m, &opts); err != nil {
+ break
+ }
+ obj = args[1]
default:
err = errors.New("too many arguments to jsonify")
}
@@ -86,5 +92,25 @@ func (ns *Namespace) Jsonify(args ...any) (template.HTML, error) {
return "", err
}
+ buff := bp.GetBuffer()
+ defer bp.PutBuffer(buff)
+ e := json.NewEncoder(buff)
+ e.SetEscapeHTML(!opts.NoHTMLEscape)
+ e.SetIndent(opts.Prefix, opts.Indent)
+ if err = e.Encode(obj); err != nil {
+ return "", err
+ }
+ b = buff.Bytes()
+ // See https://github.com/golang/go/issues/37083
+ // Hugo changed from MarshalIndent/Marshal. To make the output
+ // the same, we need to trim the trailing newline.
+ b = b[:len(b)-1]
+
return template.HTML(b), nil
}
+
+type jsonifyOpts struct {
+ Prefix string
+ Indent string
+ NoHTMLEscape bool
+}
diff --git a/tpl/encoding/encoding_test.go b/tpl/encoding/encoding_test.go
index e7c82e3be..8e6e2da48 100644
--- a/tpl/encoding/encoding_test.go
+++ b/tpl/encoding/encoding_test.go
@@ -82,7 +82,7 @@ func TestJsonify(t *testing.T) {
c := qt.New(t)
ns := New()
- for _, test := range []struct {
+ for i, test := range []struct {
opts any
v any
expect any
@@ -91,6 +91,9 @@ func TestJsonify(t *testing.T) {
{map[string]string{"indent": "<i>"}, []string{"a", "b"}, template.HTML("[\n<i>\"a\",\n<i>\"b\"\n]")},
{map[string]string{"prefix": "<p>"}, []string{"a", "b"}, template.HTML("[\n<p>\"a\",\n<p>\"b\"\n<p>]")},
{map[string]string{"prefix": "<p>", "indent": "<i>"}, []string{"a", "b"}, template.HTML("[\n<p><i>\"a\",\n<p><i>\"b\"\n<p>]")},
+ {map[string]string{"indent": "<i>"}, []string{"a", "b"}, template.HTML("[\n<i>\"a\",\n<i>\"b\"\n]")},
+ {map[string]any{"noHTMLEscape": false}, []string{"<a>", "<b>"}, template.HTML("[\"\\u003ca\\u003e\",\"\\u003cb\\u003e\"]")},
+ {map[string]any{"noHTMLEscape": true}, []string{"<a>", "<b>"}, template.HTML("[\"<a>\",\"<b>\"]")},
{nil, tstNoStringer{}, template.HTML("{}")},
{nil, nil, template.HTML("null")},
// errors
@@ -108,11 +111,11 @@ func TestJsonify(t *testing.T) {
result, err := ns.Jsonify(args...)
if b, ok := test.expect.(bool); ok && !b {
- c.Assert(err, qt.Not(qt.IsNil))
+ c.Assert(err, qt.Not(qt.IsNil), qt.Commentf("#%d", i))
continue
}
c.Assert(err, qt.IsNil)
- c.Assert(result, qt.Equals, test.expect)
+ c.Assert(result, qt.Equals, test.expect, qt.Commentf("#%d", i))
}
}