hugo

Fork of github.com/gohugoio/hugo with reverse pagination support

git clone git://git.shimmy1996.com/hugo.git

content.go (2717B)

    1 // Copyright 2011 The Go Authors. All rights reserved.
    2 // Use of this source code is governed by a BSD-style
    3 // license that can be found in the LICENSE file.
    4 
    5 package template
    6 
    7 import (
    8 	"fmt"
    9 	htmltemplate "html/template"
   10 	"reflect"
   11 )
   12 
   13 type contentType uint8
   14 
   15 const (
   16 	contentTypePlain contentType = iota
   17 	contentTypeCSS
   18 	contentTypeHTML
   19 	contentTypeHTMLAttr
   20 	contentTypeJS
   21 	contentTypeJSStr
   22 	contentTypeURL
   23 	contentTypeSrcset
   24 	// contentTypeUnsafe is used in attr.go for values that affect how
   25 	// embedded content and network messages are formed, vetted,
   26 	// or interpreted; or which credentials network messages carry.
   27 	contentTypeUnsafe
   28 )
   29 
   30 // indirect returns the value, after dereferencing as many times
   31 // as necessary to reach the base type (or nil).
   32 func indirect(a any) any {
   33 	if a == nil {
   34 		return nil
   35 	}
   36 	if t := reflect.TypeOf(a); t.Kind() != reflect.Pointer {
   37 		// Avoid creating a reflect.Value if it's not a pointer.
   38 		return a
   39 	}
   40 	v := reflect.ValueOf(a)
   41 	for v.Kind() == reflect.Pointer && !v.IsNil() {
   42 		v = v.Elem()
   43 	}
   44 	return v.Interface()
   45 }
   46 
   47 var (
   48 	errorType       = reflect.TypeOf((*error)(nil)).Elem()
   49 	fmtStringerType = reflect.TypeOf((*fmt.Stringer)(nil)).Elem()
   50 )
   51 
   52 // indirectToStringerOrError returns the value, after dereferencing as many times
   53 // as necessary to reach the base type (or nil) or an implementation of fmt.Stringer
   54 // or error,
   55 func indirectToStringerOrError(a any) any {
   56 	if a == nil {
   57 		return nil
   58 	}
   59 	v := reflect.ValueOf(a)
   60 	for !v.Type().Implements(fmtStringerType) && !v.Type().Implements(errorType) && v.Kind() == reflect.Pointer && !v.IsNil() {
   61 		v = v.Elem()
   62 	}
   63 	return v.Interface()
   64 }
   65 
   66 // stringify converts its arguments to a string and the type of the content.
   67 // All pointers are dereferenced, as in the text/template package.
   68 func stringify(args ...any) (string, contentType) {
   69 	if len(args) == 1 {
   70 		switch s := indirect(args[0]).(type) {
   71 		case string:
   72 			return s, contentTypePlain
   73 		case htmltemplate.CSS:
   74 			return string(s), contentTypeCSS
   75 		case htmltemplate.HTML:
   76 			return string(s), contentTypeHTML
   77 		case htmltemplate.HTMLAttr:
   78 			return string(s), contentTypeHTMLAttr
   79 		case htmltemplate.JS:
   80 			return string(s), contentTypeJS
   81 		case htmltemplate.JSStr:
   82 			return string(s), contentTypeJSStr
   83 		case htmltemplate.URL:
   84 			return string(s), contentTypeURL
   85 		case htmltemplate.Srcset:
   86 			return string(s), contentTypeSrcset
   87 		}
   88 	}
   89 	i := 0
   90 	for _, arg := range args {
   91 		// We skip untyped nil arguments for backward compatibility.
   92 		// Without this they would be output as <nil>, escaped.
   93 		// See issue 25875.
   94 		if arg == nil {
   95 			continue
   96 		}
   97 
   98 		args[i] = indirectToStringerOrError(arg)
   99 		i++
  100 	}
  101 	return fmt.Sprint(args[:i]...), contentTypePlain
  102 }