default.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. // Copyright 2016 José Santos <henrique_1609@me.com>
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package jet
  15. import (
  16. "encoding/json"
  17. "errors"
  18. "fmt"
  19. "html"
  20. "io"
  21. "io/ioutil"
  22. "net/url"
  23. "reflect"
  24. "strings"
  25. "text/template"
  26. )
  27. var defaultVariables map[string]reflect.Value
  28. func init() {
  29. defaultVariables = map[string]reflect.Value{
  30. "lower": reflect.ValueOf(strings.ToLower),
  31. "upper": reflect.ValueOf(strings.ToUpper),
  32. "hasPrefix": reflect.ValueOf(strings.HasPrefix),
  33. "hasSuffix": reflect.ValueOf(strings.HasSuffix),
  34. "repeat": reflect.ValueOf(strings.Repeat),
  35. "replace": reflect.ValueOf(strings.Replace),
  36. "split": reflect.ValueOf(strings.Split),
  37. "trimSpace": reflect.ValueOf(strings.TrimSpace),
  38. "html": reflect.ValueOf(html.EscapeString),
  39. "url": reflect.ValueOf(url.QueryEscape),
  40. "safeHtml": reflect.ValueOf(SafeWriter(template.HTMLEscape)),
  41. "safeJs": reflect.ValueOf(SafeWriter(template.JSEscape)),
  42. "raw": reflect.ValueOf(SafeWriter(unsafePrinter)),
  43. "unsafe": reflect.ValueOf(SafeWriter(unsafePrinter)),
  44. "writeJson": reflect.ValueOf(jsonRenderer),
  45. "json": reflect.ValueOf(json.Marshal),
  46. "map": reflect.ValueOf(newMap),
  47. "slice": reflect.ValueOf(newSlice),
  48. "array": reflect.ValueOf(newSlice),
  49. "isset": reflect.ValueOf(Func(func(a Arguments) reflect.Value {
  50. a.RequireNumOfArguments("isset", 1, -1)
  51. for i := 0; i < a.NumOfArguments(); i++ {
  52. if !a.IsSet(i) {
  53. return valueBoolFALSE
  54. }
  55. }
  56. return valueBoolTRUE
  57. })),
  58. "len": reflect.ValueOf(Func(func(a Arguments) reflect.Value {
  59. a.RequireNumOfArguments("len", 1, 1)
  60. expression := a.Get(0)
  61. if !expression.IsValid() {
  62. a.Panicf("len(): argument is not a valid value")
  63. }
  64. if expression.Kind() == reflect.Ptr || expression.Kind() == reflect.Interface {
  65. expression = expression.Elem()
  66. }
  67. switch expression.Kind() {
  68. case reflect.Array, reflect.Chan, reflect.Slice, reflect.Map, reflect.String:
  69. return reflect.ValueOf(expression.Len())
  70. case reflect.Struct:
  71. return reflect.ValueOf(expression.NumField())
  72. }
  73. a.Panicf("len(): invalid value type %s", expression.Type())
  74. return reflect.Value{}
  75. })),
  76. "includeIfExists": reflect.ValueOf(Func(func(a Arguments) reflect.Value {
  77. a.RequireNumOfArguments("includeIfExists", 1, 2)
  78. t, err := a.runtime.set.GetTemplate(a.Get(0).String())
  79. // If template exists but returns an error then panic instead of failing silently
  80. if t != nil && err != nil {
  81. panic(fmt.Errorf("including %s: %w", a.Get(0).String(), err))
  82. }
  83. if err != nil {
  84. return hiddenFalse
  85. }
  86. a.runtime.newScope()
  87. defer a.runtime.releaseScope()
  88. a.runtime.blocks = t.processedBlocks
  89. root := t.Root
  90. if t.extends != nil {
  91. root = t.extends.Root
  92. }
  93. if a.NumOfArguments() > 1 {
  94. c := a.runtime.context
  95. defer func() { a.runtime.context = c }()
  96. a.runtime.context = a.Get(1)
  97. }
  98. a.runtime.executeList(root)
  99. return hiddenTrue
  100. })),
  101. "exec": reflect.ValueOf(Func(func(a Arguments) (result reflect.Value) {
  102. a.RequireNumOfArguments("exec", 1, 2)
  103. t, err := a.runtime.set.GetTemplate(a.Get(0).String())
  104. if err != nil {
  105. panic(fmt.Errorf("exec(%s, %v): %w", a.Get(0), a.Get(1), err))
  106. }
  107. a.runtime.newScope()
  108. defer a.runtime.releaseScope()
  109. w := a.runtime.Writer
  110. defer func() { a.runtime.Writer = w }()
  111. a.runtime.Writer = ioutil.Discard
  112. a.runtime.blocks = t.processedBlocks
  113. root := t.Root
  114. if t.extends != nil {
  115. root = t.extends.Root
  116. }
  117. if a.NumOfArguments() > 1 {
  118. c := a.runtime.context
  119. defer func() { a.runtime.context = c }()
  120. a.runtime.context = a.Get(1)
  121. }
  122. result = a.runtime.executeList(root)
  123. return result
  124. })),
  125. "ints": reflect.ValueOf(Func(func(a Arguments) (result reflect.Value) {
  126. var from, to int64
  127. err := a.ParseInto(&from, &to)
  128. if err != nil {
  129. panic(err)
  130. }
  131. // check to > from
  132. if to <= from {
  133. panic(errors.New("invalid range for ints ranger: 'from' must be smaller than 'to'"))
  134. }
  135. return reflect.ValueOf(newIntsRanger(from, to))
  136. })),
  137. "dump": reflect.ValueOf(Func(func(a Arguments) (result reflect.Value) {
  138. switch numArgs := a.NumOfArguments(); numArgs {
  139. case 0:
  140. // no arguments were provided, dump all; do not recurse over parents
  141. return dumpAll(a, 0)
  142. case 1:
  143. if arg := a.Get(0); arg.Kind() == reflect.Float64 {
  144. // dump all, maybe walk into parents
  145. return dumpAll(a, int(arg.Float()))
  146. }
  147. fallthrough
  148. default:
  149. // one or more arguments were provided, grab them and check they are all strings
  150. ids := make([]string, numArgs)
  151. for i := range ids {
  152. arg := a.Get(i)
  153. if arg.Kind() != reflect.String {
  154. panic(fmt.Errorf("dump: expected argument %d to be a string, but got a %T", i, arg.Interface()))
  155. }
  156. ids = append(ids, arg.String())
  157. }
  158. return dumpIdentified(a.runtime, ids)
  159. }
  160. })),
  161. }
  162. }
  163. type hiddenBool bool
  164. func (m hiddenBool) Render(r *Runtime) { /* render nothing -> hidden */ }
  165. var hiddenTrue = reflect.ValueOf(hiddenBool(true))
  166. var hiddenFalse = reflect.ValueOf(hiddenBool(false))
  167. func jsonRenderer(v interface{}) RendererFunc {
  168. return func(r *Runtime) {
  169. err := json.NewEncoder(r.Writer).Encode(v)
  170. if err != nil {
  171. panic(err)
  172. }
  173. }
  174. }
  175. func unsafePrinter(w io.Writer, b []byte) {
  176. w.Write(b)
  177. }
  178. // SafeWriter is a function that writes bytes directly to the render output, without going through Jet's auto-escaping phase.
  179. // Use/implement this if content should be escaped differently or not at all (see raw/unsafe builtins).
  180. type SafeWriter func(io.Writer, []byte)
  181. var stringType = reflect.TypeOf("")
  182. var newMap = Func(func(a Arguments) reflect.Value {
  183. if a.NumOfArguments()%2 > 0 {
  184. panic("map(): incomplete key-value pair (even number of arguments required)")
  185. }
  186. m := reflect.ValueOf(make(map[string]interface{}, a.NumOfArguments()/2))
  187. for i := 0; i < a.NumOfArguments(); i += 2 {
  188. key := a.Get(i)
  189. if !key.IsValid() {
  190. a.Panicf("map(): key argument at position %d is not a valid value!", i)
  191. }
  192. if !key.Type().ConvertibleTo(stringType) {
  193. a.Panicf("map(): can't use %+v as string key: %s is not convertible to string", key, key.Type())
  194. }
  195. key = key.Convert(stringType)
  196. m.SetMapIndex(a.Get(i), a.Get(i+1))
  197. }
  198. return m
  199. })
  200. var newSlice = Func(func(a Arguments) reflect.Value {
  201. arr := make([]interface{}, a.NumOfArguments())
  202. for i := 0; i < a.NumOfArguments(); i++ {
  203. arr[i] = a.Get(i).Interface()
  204. }
  205. return reflect.ValueOf(arr)
  206. })