defaults.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. package sprig
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "reflect"
  6. "slices"
  7. "strings"
  8. )
  9. // defaultValue checks whether `given` is set, and returns default if not set.
  10. //
  11. // This returns `d` if `given` appears not to be set, and `given` otherwise.
  12. //
  13. // For numeric types 0 is unset.
  14. // For strings, maps, arrays, and slices, len() = 0 is considered unset.
  15. // For bool, false is unset.
  16. // Structs are never considered unset.
  17. //
  18. // For everything else, including pointers, a nil value is unset.
  19. func defaultValue(d any, given ...any) any {
  20. if empty(given) || empty(given[0]) {
  21. return d
  22. }
  23. return given[0]
  24. }
  25. // empty returns true if the given value has the zero value for its type.
  26. // This is a helper function used by defaultValue, coalesce, all, and anyNonEmpty.
  27. //
  28. // The following values are considered empty:
  29. // - Invalid values
  30. // - nil values
  31. // - Zero-length arrays, slices, maps, and strings
  32. // - Boolean false
  33. // - Zero for all numeric types
  34. // - Structs are never considered empty
  35. //
  36. // Parameters:
  37. // - given: The value to check for emptiness
  38. //
  39. // Returns:
  40. // - bool: True if the value is considered empty, false otherwise
  41. func empty(given any) bool {
  42. g := reflect.ValueOf(given)
  43. if !g.IsValid() {
  44. return true
  45. }
  46. // Basically adapted from text/template.isTrue
  47. switch g.Kind() {
  48. default:
  49. return g.IsNil()
  50. case reflect.Array, reflect.Slice, reflect.Map, reflect.String:
  51. return g.Len() == 0
  52. case reflect.Bool:
  53. return !g.Bool()
  54. case reflect.Complex64, reflect.Complex128:
  55. return g.Complex() == 0
  56. case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
  57. return g.Int() == 0
  58. case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
  59. return g.Uint() == 0
  60. case reflect.Float32, reflect.Float64:
  61. return g.Float() == 0
  62. case reflect.Struct:
  63. return false
  64. }
  65. }
  66. // coalesce returns the first non-empty value from a list of values.
  67. // If all values are empty, it returns nil.
  68. //
  69. // This is useful for providing a series of fallback values.
  70. //
  71. // Parameters:
  72. // - v: A variadic list of values to check
  73. //
  74. // Returns:
  75. // - any: The first non-empty value, or nil if all values are empty
  76. func coalesce(v ...any) any {
  77. for _, val := range v {
  78. if !empty(val) {
  79. return val
  80. }
  81. }
  82. return nil
  83. }
  84. // all checks if all values in a list are non-empty.
  85. // Returns true if every value in the list is non-empty.
  86. // If the list is empty, returns true (vacuously true).
  87. //
  88. // Parameters:
  89. // - v: A variadic list of values to check
  90. //
  91. // Returns:
  92. // - bool: True if all values are non-empty, false otherwise
  93. func all(v ...any) bool {
  94. return !slices.ContainsFunc(v, empty)
  95. }
  96. // anyNonEmpty checks if at least one value in a list is non-empty.
  97. // Returns true if any value in the list is non-empty.
  98. // If the list is empty, returns false.
  99. //
  100. // Parameters:
  101. // - v: A variadic list of values to check
  102. //
  103. // Returns:
  104. // - bool: True if at least one value is non-empty, false otherwise
  105. func anyNonEmpty(v ...any) bool {
  106. for _, val := range v {
  107. if !empty(val) {
  108. return true
  109. }
  110. }
  111. return false
  112. }
  113. // fromJSON decodes a JSON string into a structured value.
  114. // This function ignores any errors that occur during decoding.
  115. // If the JSON is invalid, it returns nil.
  116. //
  117. // Parameters:
  118. // - v: The JSON string to decode
  119. //
  120. // Returns:
  121. // - any: The decoded value, or nil if decoding failed
  122. func fromJSON(v string) any {
  123. output, _ := mustFromJSON(v)
  124. return output
  125. }
  126. // mustFromJSON decodes a JSON string into a structured value.
  127. // Unlike fromJSON, this function returns any errors that occur during decoding.
  128. //
  129. // Parameters:
  130. // - v: The JSON string to decode
  131. //
  132. // Returns:
  133. // - any: The decoded value
  134. // - error: Any error that occurred during decoding
  135. func mustFromJSON(v string) (any, error) {
  136. var output any
  137. err := json.Unmarshal([]byte(v), &output)
  138. return output, err
  139. }
  140. // toJSON encodes a value into a JSON string.
  141. // This function ignores any errors that occur during encoding.
  142. // If the value cannot be encoded, it returns an empty string.
  143. //
  144. // Parameters:
  145. // - v: The value to encode to JSON
  146. //
  147. // Returns:
  148. // - string: The JSON string representation of the value
  149. func toJSON(v any) string {
  150. output, _ := json.Marshal(v)
  151. return string(output)
  152. }
  153. // mustToJSON encodes a value into a JSON string.
  154. // Unlike toJSON, this function returns any errors that occur during encoding.
  155. //
  156. // Parameters:
  157. // - v: The value to encode to JSON
  158. //
  159. // Returns:
  160. // - string: The JSON string representation of the value
  161. // - error: Any error that occurred during encoding
  162. func mustToJSON(v any) (string, error) {
  163. output, err := json.Marshal(v)
  164. if err != nil {
  165. return "", err
  166. }
  167. return string(output), nil
  168. }
  169. // toPrettyJSON encodes a value into a pretty (indented) JSON string.
  170. // This function ignores any errors that occur during encoding.
  171. // If the value cannot be encoded, it returns an empty string.
  172. //
  173. // Parameters:
  174. // - v: The value to encode to JSON
  175. //
  176. // Returns:
  177. // - string: The indented JSON string representation of the value
  178. func toPrettyJSON(v any) string {
  179. output, _ := json.MarshalIndent(v, "", " ")
  180. return string(output)
  181. }
  182. // mustToPrettyJSON encodes a value into a pretty (indented) JSON string.
  183. // Unlike toPrettyJSON, this function returns any errors that occur during encoding.
  184. //
  185. // Parameters:
  186. // - v: The value to encode to JSON
  187. //
  188. // Returns:
  189. // - string: The indented JSON string representation of the value
  190. // - error: Any error that occurred during encoding
  191. func mustToPrettyJSON(v any) (string, error) {
  192. output, err := json.MarshalIndent(v, "", " ")
  193. if err != nil {
  194. return "", err
  195. }
  196. return string(output), nil
  197. }
  198. // toRawJSON encodes a value into a JSON string with no escaping of HTML characters.
  199. // This function panics if an error occurs during encoding.
  200. // Unlike toJSON, HTML characters like <, >, and & are not escaped.
  201. //
  202. // Parameters:
  203. // - v: The value to encode to JSON
  204. //
  205. // Returns:
  206. // - string: The JSON string representation of the value without HTML escaping
  207. func toRawJSON(v any) string {
  208. output, err := mustToRawJSON(v)
  209. if err != nil {
  210. panic(err)
  211. }
  212. return output
  213. }
  214. // mustToRawJSON encodes a value into a JSON string with no escaping of HTML characters.
  215. // Unlike toRawJSON, this function returns any errors that occur during encoding.
  216. // HTML characters like <, >, and & are not escaped in the output.
  217. //
  218. // Parameters:
  219. // - v: The value to encode to JSON
  220. //
  221. // Returns:
  222. // - string: The JSON string representation of the value without HTML escaping
  223. // - error: Any error that occurred during encoding
  224. func mustToRawJSON(v any) (string, error) {
  225. buf := new(bytes.Buffer)
  226. enc := json.NewEncoder(buf)
  227. enc.SetEscapeHTML(false)
  228. if err := enc.Encode(&v); err != nil {
  229. return "", err
  230. }
  231. return strings.TrimSuffix(buf.String(), "\n"), nil
  232. }
  233. // ternary implements a conditional (ternary) operator.
  234. // It returns the first value if the condition is true, otherwise returns the second value.
  235. // This is similar to the ?: operator in many programming languages.
  236. //
  237. // Parameters:
  238. // - vt: The value to return if the condition is true
  239. // - vf: The value to return if the condition is false
  240. // - v: The boolean condition to evaluate
  241. //
  242. // Returns:
  243. // - any: Either vt or vf depending on the value of v
  244. func ternary(vt any, vf any, v bool) any {
  245. if v {
  246. return vt
  247. }
  248. return vf
  249. }