defaults.go 7.2 KB

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