shithub: hugo

Download patch

ref: 5498a1bd5616903fce3df687adf43d19e1c4e4c4
parent: d3627b1747c18eb18279012afe5ba7174bdaa869
author: Cameron Moore <[email protected]>
date: Fri Aug 12 13:43:15 EDT 2016

tpl: Return all errors from casting

Most non-boolean template functions should return errors.

Fixes #2354

--- a/tpl/template_funcs.go
+++ b/tpl/template_funcs.go
@@ -447,7 +447,10 @@
 		return nil, err
 	}
 
-	conv := cast.ToString(content)
+	conv, err := cast.ToStringE(content)
+	if err != nil {
+		return nil, err
+	}
 	if len(limit) > 0 {
 		return re.FindAllString(conv, limit[0]), nil
 	}
@@ -1204,12 +1207,15 @@
 var markdownTrimSuffix = []byte("</p>\n")
 
 // markdownify renders a given string from Markdown to HTML.
-func markdownify(in interface{}) template.HTML {
-	text := cast.ToString(in)
+func markdownify(in interface{}) (template.HTML, error) {
+	text, err := cast.ToStringE(in)
+	if err != nil {
+		return "", err
+	}
 	m := helpers.RenderBytes(&helpers.RenderingContext{Content: []byte(text), PageFmt: "markdown"})
 	m = bytes.TrimPrefix(m, markdownTrimPrefix)
 	m = bytes.TrimSuffix(m, markdownTrimSuffix)
-	return template.HTML(m)
+	return template.HTML(m), nil
 }
 
 // jsonify encodes a given object to JSON.
@@ -1219,7 +1225,6 @@
 		return "", err
 	}
 	return template.HTML(b), nil
-
 }
 
 // emojify "emojifies" the given string.
@@ -1568,15 +1573,21 @@
 // It returns the contents as a string.
 // There is a upper size limit set at 1 megabytes.
 func readFileFromWorkingDir(i interface{}) (string, error) {
-	return readFile(hugofs.WorkingDir(), cast.ToString(i))
+	s, err := cast.ToStringE(i)
+	if err != nil {
+		return "", err
+	}
+	return readFile(hugofs.WorkingDir(), s)
 }
 
 // readDirFromWorkingDir listst the directory content relative to the
 // configured WorkingDir.
 func readDirFromWorkingDir(i interface{}) ([]os.FileInfo, error) {
+	path, err := cast.ToStringE(i)
+	if err != nil {
+		return nil, err
+	}
 
-	path := cast.ToString(i)
-
 	list, err := afero.ReadDir(hugofs.WorkingDir(), path)
 
 	if err != nil {
@@ -1587,25 +1598,34 @@
 }
 
 // safeHTMLAttr returns a given string as html/template HTMLAttr content.
-func safeHTMLAttr(a interface{}) template.HTMLAttr {
-	return template.HTMLAttr(cast.ToString(a))
+func safeHTMLAttr(a interface{}) (template.HTMLAttr, error) {
+	s, err := cast.ToStringE(a)
+	return template.HTMLAttr(s), err
 }
 
 // safeCSS returns a given string as html/template CSS content.
-func safeCSS(a interface{}) template.CSS {
-	return template.CSS(cast.ToString(a))
+func safeCSS(a interface{}) (template.CSS, error) {
+	s, err := cast.ToStringE(a)
+	return template.CSS(s), err
 }
 
 // safeURL returns a given string as html/template URL content.
-func safeURL(a interface{}) template.URL {
-	return template.URL(cast.ToString(a))
+func safeURL(a interface{}) (template.URL, error) {
+	s, err := cast.ToStringE(a)
+	return template.URL(s), err
 }
 
 // safeHTML returns a given string as html/template HTML content.
-func safeHTML(a interface{}) template.HTML { return template.HTML(cast.ToString(a)) }
+func safeHTML(a interface{}) (template.HTML, error) {
+	s, err := cast.ToStringE(a)
+	return template.HTML(s), err
+}
 
 // safeJS returns the given string as a html/template JS content.
-func safeJS(a interface{}) template.JS { return template.JS(cast.ToString(a)) }
+func safeJS(a interface{}) (template.JS, error) {
+	s, err := cast.ToStringE(a)
+	return template.JS(s), err
+}
 
 // mod returns a % b.
 func mod(a, b interface{}) (int64, error) {
@@ -1801,9 +1821,25 @@
 	return html.UnescapeString(conv), nil
 }
 
+func absURL(a interface{}) (template.HTML, error) {
+	s, err := cast.ToStringE(a)
+	if err != nil {
+		return "", nil
+	}
+	return template.HTML(helpers.AbsURL(s)), nil
+}
+
+func relURL(a interface{}) (template.HTML, error) {
+	s, err := cast.ToStringE(a)
+	if err != nil {
+		return "", nil
+	}
+	return template.HTML(helpers.RelURL(s)), nil
+}
+
 func init() {
 	funcMap = template.FuncMap{
-		"absURL":       func(a interface{}) template.HTML { return template.HTML(helpers.AbsURL(cast.ToString(a))) },
+		"absURL":       absURL,
 		"add":          func(a, b interface{}) (interface{}, error) { return helpers.DoArithmetic(a, b, '+') },
 		"after":        after,
 		"apply":        apply,
@@ -1834,7 +1870,7 @@
 		"humanize":     humanize,
 		"in":           in,
 		"index":        index,
-		"int":          func(v interface{}) int { return cast.ToInt(v) },
+		"int":          func(v interface{}) (int, error) { return cast.ToIntE(v) },
 		"intersect":    intersect,
 		"isSet":        isSet,
 		"isset":        isSet,
@@ -1856,7 +1892,7 @@
 		"readDir":      readDirFromWorkingDir,
 		"readFile":     readFileFromWorkingDir,
 		"ref":          ref,
-		"relURL":       func(a interface{}) template.HTML { return template.HTML(helpers.RelURL(cast.ToString(a))) },
+		"relURL":       relURL,
 		"relref":       relRef,
 		"replace":      replace,
 		"replaceRE":    replaceRE,
@@ -1875,7 +1911,7 @@
 		"slicestr":     slicestr,
 		"sort":         sortSeq,
 		"split":        split,
-		"string":       func(v interface{}) string { return cast.ToString(v) },
+		"string":       func(v interface{}) (string, error) { return cast.ToStringE(v) },
 		"sub":          func(a, b interface{}) (interface{}, error) { return helpers.DoArithmetic(a, b, '-') },
 		"substr":       substr,
 		"title":        func(a string) string { return strings.Title(a) },
--- a/tpl/template_funcs_test.go
+++ b/tpl/template_funcs_test.go
@@ -1740,7 +1740,10 @@
 		{"Hello **World!**", template.HTML("Hello <strong>World!</strong>")},
 		{[]byte("Hello Bytes **World!**"), template.HTML("Hello Bytes <strong>World!</strong>")},
 	} {
-		result := markdownify(this.in)
+		result, err := markdownify(this.in)
+		if err != nil {
+			t.Fatalf("[%d] unexpected error in markdownify", i, err)
+		}
 		if !reflect.DeepEqual(result, this.expect) {
 			t.Errorf("[%d] markdownify got %v (type %v) but expected %v (type %v)", i, result, reflect.TypeOf(result), this.expect, reflect.TypeOf(this.expect))
 		}
@@ -2127,12 +2130,17 @@
 		}
 
 		buf.Reset()
-		err = tmpl.Execute(buf, safeHTML(this.str))
+		v, err := safeHTML(this.str)
 		if err != nil {
-			t.Errorf("[%d] execute template with an escaped string value by SafeHTML returns unexpected error: %s", i, err)
+			t.Fatalf("[%d] unexpected error in safeHTML: %s", i, err)
 		}
+
+		err = tmpl.Execute(buf, v)
+		if err != nil {
+			t.Errorf("[%d] execute template with an escaped string value by safeHTML returns unexpected error: %s", i, err)
+		}
 		if buf.String() != this.expectWithEscape {
-			t.Errorf("[%d] execute template with an escaped string value by SafeHTML, got %v but expected %v", i, buf.String(), this.expectWithEscape)
+			t.Errorf("[%d] execute template with an escaped string value by safeHTML, got %v but expected %v", i, buf.String(), this.expectWithEscape)
 		}
 	}
 }
@@ -2162,12 +2170,17 @@
 		}
 
 		buf.Reset()
-		err = tmpl.Execute(buf, safeHTMLAttr(this.str))
+		v, err := safeHTMLAttr(this.str)
 		if err != nil {
-			t.Errorf("[%d] execute template with an escaped string value by SafeHTMLAttr returns unexpected error: %s", i, err)
+			t.Fatalf("[%d] unexpected error in safeHTMLAttr: %s", i, err)
 		}
+
+		err = tmpl.Execute(buf, v)
+		if err != nil {
+			t.Errorf("[%d] execute template with an escaped string value by safeHTMLAttr returns unexpected error: %s", i, err)
+		}
 		if buf.String() != this.expectWithEscape {
-			t.Errorf("[%d] execute template with an escaped string value by SafeHTMLAttr, got %v but expected %v", i, buf.String(), this.expectWithEscape)
+			t.Errorf("[%d] execute template with an escaped string value by safeHTMLAttr, got %v but expected %v", i, buf.String(), this.expectWithEscape)
 		}
 	}
 }
@@ -2197,12 +2210,17 @@
 		}
 
 		buf.Reset()
-		err = tmpl.Execute(buf, safeCSS(this.str))
+		v, err := safeCSS(this.str)
 		if err != nil {
-			t.Errorf("[%d] execute template with an escaped string value by SafeCSS returns unexpected error: %s", i, err)
+			t.Fatalf("[%d] unexpected error in safeCSS: %s", i, err)
 		}
+
+		err = tmpl.Execute(buf, v)
+		if err != nil {
+			t.Errorf("[%d] execute template with an escaped string value by safeCSS returns unexpected error: %s", i, err)
+		}
 		if buf.String() != this.expectWithEscape {
-			t.Errorf("[%d] execute template with an escaped string value by SafeCSS, got %v but expected %v", i, buf.String(), this.expectWithEscape)
+			t.Errorf("[%d] execute template with an escaped string value by safeCSS, got %v but expected %v", i, buf.String(), this.expectWithEscape)
 		}
 	}
 }
@@ -2232,12 +2250,17 @@
 		}
 
 		buf.Reset()
-		err = tmpl.Execute(buf, safeJS(this.str))
+		v, err := safeJS(this.str)
 		if err != nil {
-			t.Errorf("[%d] execute template with an escaped string value by SafeJS returns unexpected error: %s", i, err)
+			t.Fatalf("[%d] unexpected error in safeJS: %s", i, err)
 		}
+
+		err = tmpl.Execute(buf, v)
+		if err != nil {
+			t.Errorf("[%d] execute template with an escaped string value by safeJS returns unexpected error: %s", i, err)
+		}
 		if buf.String() != this.expectWithEscape {
-			t.Errorf("[%d] execute template with an escaped string value by SafeJS, got %v but expected %v", i, buf.String(), this.expectWithEscape)
+			t.Errorf("[%d] execute template with an escaped string value by safeJS, got %v but expected %v", i, buf.String(), this.expectWithEscape)
 		}
 	}
 }
@@ -2267,12 +2290,17 @@
 		}
 
 		buf.Reset()
-		err = tmpl.Execute(buf, safeURL(this.str))
+		v, err := safeURL(this.str)
 		if err != nil {
-			t.Errorf("[%d] execute template with an escaped string value by SafeURL returns unexpected error: %s", i, err)
+			t.Fatalf("[%d] unexpected error in safeURL: %s", i, err)
 		}
+
+		err = tmpl.Execute(buf, v)
+		if err != nil {
+			t.Errorf("[%d] execute template with an escaped string value by safeURL returns unexpected error: %s", i, err)
+		}
 		if buf.String() != this.expectWithEscape {
-			t.Errorf("[%d] execute template with an escaped string value by SafeURL, got %v but expected %v", i, buf.String(), this.expectWithEscape)
+			t.Errorf("[%d] execute template with an escaped string value by safeURL, got %v but expected %v", i, buf.String(), this.expectWithEscape)
 		}
 	}
 }