blob: 848cdaec8d9750a98d02986c381037044752aff8 [file] [log] [blame]
// Copyright 2021 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package site
import (
"fmt"
"reflect"
"strings"
"golang.org/x/website/internal/backport/html/template"
"golang.org/x/website/internal/tmplfunc"
"gopkg.in/yaml.v3"
)
func (site *Site) initTemplate() error {
funcs := template.FuncMap{
"add": func(i, j int) int { return i + j },
"data": site.data,
"dict": dict,
"first": first,
"markdown": markdown,
"newest": newest,
"page": site.pageByPath,
"pages": site.pagesGlob,
"replace": replace,
"rawhtml": rawhtml,
"trim": strings.Trim,
"yaml": yamlFn,
}
site.base = template.New("site").Funcs(funcs)
if err := tmplfunc.ParseGlob(site.base, site.file("_templates/*.tmpl")); err != nil && !strings.Contains(err.Error(), "pattern matches no files") {
return err
}
return nil
}
func (site *Site) clone() *template.Template {
t := template.Must(site.base.Clone())
if err := tmplfunc.Funcs(t); err != nil {
panic(err)
}
return t
}
func toString(x interface{}) string {
switch x := x.(type) {
case string:
return x
case template.HTML:
return string(x)
case nil:
return ""
default:
panic(fmt.Sprintf("cannot toString %T", x))
}
}
func first(n int, list reflect.Value) reflect.Value {
if !list.IsValid() {
return list
}
if list.Kind() == reflect.Interface {
if list.IsNil() {
return list
}
list = list.Elem()
}
if list.Len() < n {
return list
}
return list.Slice(0, n)
}
func dict(args ...interface{}) map[string]interface{} {
m := make(map[string]interface{})
for i := 0; i < len(args); i += 2 {
m[args[i].(string)] = args[i+1]
}
m["Identifier"] = "IDENT"
return m
}
func list(args ...interface{}) []interface{} {
return args
}
// markdown is the function provided to templates.
func markdown(data interface{}) (template.HTML, error) {
h, err := markdownToHTML(toString(data))
if err != nil {
return "", err
}
s := strings.TrimSpace(string(h))
if strings.HasPrefix(s, "<p>") && strings.HasSuffix(s, "</p>") && strings.Count(s, "<p>") == 1 {
h = template.HTML(strings.TrimSpace(s[len("<p>") : len(s)-len("</p>")]))
}
return h, nil
}
func replace(input, x, y interface{}) string {
return strings.ReplaceAll(toString(input), toString(x), toString(y))
}
func rawhtml(s interface{}) template.HTML {
return template.HTML(toString(s))
}
func yamlFn(s string) (interface{}, error) {
var d interface{}
if err := yaml.Unmarshal([]byte(s), &d); err != nil {
return nil, err
}
return d, nil
}