list.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. package sprig
  2. import (
  3. "fmt"
  4. "math"
  5. "reflect"
  6. "sort"
  7. )
  8. // Reflection is used in these functions so that slices and arrays of strings,
  9. // ints, and other types not implementing []any can be worked with.
  10. // For example, this is useful if you need to work on the output of regexs.
  11. // list creates a new list (slice) containing the provided arguments.
  12. // It accepts any number of arguments of any type and returns them as a slice.
  13. func list(v ...any) []any {
  14. return v
  15. }
  16. // push appends an element to the end of a list (slice or array).
  17. // It takes a list and a value, and returns a new list with the value appended.
  18. // This function will panic if the first argument is not a slice or array.
  19. func push(list any, v any) []any {
  20. l, err := mustPush(list, v)
  21. if err != nil {
  22. panic(err)
  23. }
  24. return l
  25. }
  26. // mustPush is the implementation of push that returns an error instead of panicking.
  27. // It converts the input list to a slice of any type, then appends the value.
  28. func mustPush(list any, v any) ([]any, error) {
  29. tp := reflect.TypeOf(list).Kind()
  30. switch tp {
  31. case reflect.Slice, reflect.Array:
  32. l2 := reflect.ValueOf(list)
  33. l := l2.Len()
  34. nl := make([]any, l)
  35. for i := 0; i < l; i++ {
  36. nl[i] = l2.Index(i).Interface()
  37. }
  38. return append(nl, v), nil
  39. default:
  40. return nil, fmt.Errorf("cannot push on type %s", tp)
  41. }
  42. }
  43. // prepend adds an element to the beginning of a list (slice or array).
  44. // It takes a list and a value, and returns a new list with the value at the start.
  45. // This function will panic if the first argument is not a slice or array.
  46. func prepend(list any, v any) []any {
  47. l, err := mustPrepend(list, v)
  48. if err != nil {
  49. panic(err)
  50. }
  51. return l
  52. }
  53. // mustPrepend is the implementation of prepend that returns an error instead of panicking.
  54. // It converts the input list to a slice of any type, then prepends the value.
  55. func mustPrepend(list any, v any) ([]any, error) {
  56. tp := reflect.TypeOf(list).Kind()
  57. switch tp {
  58. case reflect.Slice, reflect.Array:
  59. l2 := reflect.ValueOf(list)
  60. l := l2.Len()
  61. nl := make([]any, l)
  62. for i := 0; i < l; i++ {
  63. nl[i] = l2.Index(i).Interface()
  64. }
  65. return append([]any{v}, nl...), nil
  66. default:
  67. return nil, fmt.Errorf("cannot prepend on type %s", tp)
  68. }
  69. }
  70. // chunk divides a list into sub-lists of the specified size.
  71. // It takes a size and a list, and returns a list of lists, each containing
  72. // up to 'size' elements from the original list.
  73. // This function will panic if the second argument is not a slice or array.
  74. func chunk(size int, list any) [][]any {
  75. l, err := mustChunk(size, list)
  76. if err != nil {
  77. panic(err)
  78. }
  79. return l
  80. }
  81. // mustChunk is the implementation of chunk that returns an error instead of panicking.
  82. // It divides the input list into chunks of the specified size.
  83. func mustChunk(size int, list any) ([][]any, error) {
  84. tp := reflect.TypeOf(list).Kind()
  85. switch tp {
  86. case reflect.Slice, reflect.Array:
  87. l2 := reflect.ValueOf(list)
  88. l := l2.Len()
  89. numChunks := int(math.Floor(float64(l-1)/float64(size)) + 1)
  90. if numChunks > sliceSizeLimit {
  91. return nil, fmt.Errorf("number of chunks %d exceeds maximum limit of %d", numChunks, sliceSizeLimit)
  92. }
  93. result := make([][]any, numChunks)
  94. for i := 0; i < numChunks; i++ {
  95. clen := size
  96. // Handle the last chunk which might be smaller
  97. if i == numChunks-1 {
  98. clen = int(math.Floor(math.Mod(float64(l), float64(size))))
  99. if clen == 0 {
  100. clen = size
  101. }
  102. }
  103. result[i] = make([]any, clen)
  104. for j := 0; j < clen; j++ {
  105. ix := i*size + j
  106. result[i][j] = l2.Index(ix).Interface()
  107. }
  108. }
  109. return result, nil
  110. default:
  111. return nil, fmt.Errorf("cannot chunk type %s", tp)
  112. }
  113. }
  114. // last returns the last element of a list (slice or array).
  115. // If the list is empty, it returns nil.
  116. // This function will panic if the argument is not a slice or array.
  117. func last(list any) any {
  118. l, err := mustLast(list)
  119. if err != nil {
  120. panic(err)
  121. }
  122. return l
  123. }
  124. // mustLast is the implementation of last that returns an error instead of panicking.
  125. // It returns the last element of the list or nil if the list is empty.
  126. func mustLast(list any) (any, error) {
  127. tp := reflect.TypeOf(list).Kind()
  128. switch tp {
  129. case reflect.Slice, reflect.Array:
  130. l2 := reflect.ValueOf(list)
  131. l := l2.Len()
  132. if l == 0 {
  133. return nil, nil
  134. }
  135. return l2.Index(l - 1).Interface(), nil
  136. default:
  137. return nil, fmt.Errorf("cannot find last on type %s", tp)
  138. }
  139. }
  140. // first returns the first element of a list (slice or array).
  141. // If the list is empty, it returns nil.
  142. // This function will panic if the argument is not a slice or array.
  143. func first(list any) any {
  144. l, err := mustFirst(list)
  145. if err != nil {
  146. panic(err)
  147. }
  148. return l
  149. }
  150. // mustFirst is the implementation of first that returns an error instead of panicking.
  151. // It returns the first element of the list or nil if the list is empty.
  152. func mustFirst(list any) (any, error) {
  153. tp := reflect.TypeOf(list).Kind()
  154. switch tp {
  155. case reflect.Slice, reflect.Array:
  156. l2 := reflect.ValueOf(list)
  157. l := l2.Len()
  158. if l == 0 {
  159. return nil, nil
  160. }
  161. return l2.Index(0).Interface(), nil
  162. default:
  163. return nil, fmt.Errorf("cannot find first on type %s", tp)
  164. }
  165. }
  166. // rest returns all elements of a list except the first one.
  167. // If the list is empty, it returns nil.
  168. // This function will panic if the argument is not a slice or array.
  169. func rest(list any) []any {
  170. l, err := mustRest(list)
  171. if err != nil {
  172. panic(err)
  173. }
  174. return l
  175. }
  176. // mustRest is the implementation of rest that returns an error instead of panicking.
  177. // It returns all elements of the list except the first one, or nil if the list is empty.
  178. func mustRest(list any) ([]any, error) {
  179. tp := reflect.TypeOf(list).Kind()
  180. switch tp {
  181. case reflect.Slice, reflect.Array:
  182. l2 := reflect.ValueOf(list)
  183. l := l2.Len()
  184. if l == 0 {
  185. return nil, nil
  186. }
  187. nl := make([]any, l-1)
  188. for i := 1; i < l; i++ {
  189. nl[i-1] = l2.Index(i).Interface()
  190. }
  191. return nl, nil
  192. default:
  193. return nil, fmt.Errorf("cannot find rest on type %s", tp)
  194. }
  195. }
  196. // initial returns all elements of a list except the last one.
  197. // If the list is empty, it returns nil.
  198. // This function will panic if the argument is not a slice or array.
  199. func initial(list any) []any {
  200. l, err := mustInitial(list)
  201. if err != nil {
  202. panic(err)
  203. }
  204. return l
  205. }
  206. // mustInitial is the implementation of initial that returns an error instead of panicking.
  207. // It returns all elements of the list except the last one, or nil if the list is empty.
  208. func mustInitial(list any) ([]any, error) {
  209. tp := reflect.TypeOf(list).Kind()
  210. switch tp {
  211. case reflect.Slice, reflect.Array:
  212. l2 := reflect.ValueOf(list)
  213. l := l2.Len()
  214. if l == 0 {
  215. return nil, nil
  216. }
  217. nl := make([]any, l-1)
  218. for i := 0; i < l-1; i++ {
  219. nl[i] = l2.Index(i).Interface()
  220. }
  221. return nl, nil
  222. default:
  223. return nil, fmt.Errorf("cannot find initial on type %s", tp)
  224. }
  225. }
  226. // sortAlpha sorts a list of strings alphabetically.
  227. // If the input is not a slice or array, it returns a single-element slice
  228. // containing the string representation of the input.
  229. func sortAlpha(list any) []string {
  230. k := reflect.Indirect(reflect.ValueOf(list)).Kind()
  231. switch k {
  232. case reflect.Slice, reflect.Array:
  233. a := strslice(list)
  234. s := sort.StringSlice(a)
  235. s.Sort()
  236. return s
  237. }
  238. return []string{strval(list)}
  239. }
  240. // reverse returns a new list with the elements in reverse order.
  241. // This function will panic if the argument is not a slice or array.
  242. func reverse(v any) []any {
  243. l, err := mustReverse(v)
  244. if err != nil {
  245. panic(err)
  246. }
  247. return l
  248. }
  249. // mustReverse is the implementation of reverse that returns an error instead of panicking.
  250. // It returns a new list with the elements in reverse order.
  251. func mustReverse(v any) ([]any, error) {
  252. tp := reflect.TypeOf(v).Kind()
  253. switch tp {
  254. case reflect.Slice, reflect.Array:
  255. l2 := reflect.ValueOf(v)
  256. l := l2.Len()
  257. // We do not sort in place because the incoming array should not be altered.
  258. nl := make([]any, l)
  259. for i := 0; i < l; i++ {
  260. nl[l-i-1] = l2.Index(i).Interface()
  261. }
  262. return nl, nil
  263. default:
  264. return nil, fmt.Errorf("cannot find reverse on type %s", tp)
  265. }
  266. }
  267. // compact returns a new list with all "empty" elements removed.
  268. // An element is considered empty if it's nil, zero, an empty string, or an empty collection.
  269. // This function will panic if the argument is not a slice or array.
  270. func compact(list any) []any {
  271. l, err := mustCompact(list)
  272. if err != nil {
  273. panic(err)
  274. }
  275. return l
  276. }
  277. // mustCompact is the implementation of compact that returns an error instead of panicking.
  278. // It returns a new list with all "empty" elements removed.
  279. func mustCompact(list any) ([]any, error) {
  280. tp := reflect.TypeOf(list).Kind()
  281. switch tp {
  282. case reflect.Slice, reflect.Array:
  283. l2 := reflect.ValueOf(list)
  284. l := l2.Len()
  285. var nl []any
  286. var item any
  287. for i := 0; i < l; i++ {
  288. item = l2.Index(i).Interface()
  289. if !empty(item) {
  290. nl = append(nl, item)
  291. }
  292. }
  293. return nl, nil
  294. default:
  295. return nil, fmt.Errorf("cannot compact on type %s", tp)
  296. }
  297. }
  298. // uniq returns a new list with duplicate elements removed.
  299. // The first occurrence of each element is kept.
  300. // This function will panic if the argument is not a slice or array.
  301. func uniq(list any) []any {
  302. l, err := mustUniq(list)
  303. if err != nil {
  304. panic(err)
  305. }
  306. return l
  307. }
  308. // mustUniq is the implementation of uniq that returns an error instead of panicking.
  309. // It returns a new list with duplicate elements removed.
  310. func mustUniq(list any) ([]any, error) {
  311. tp := reflect.TypeOf(list).Kind()
  312. switch tp {
  313. case reflect.Slice, reflect.Array:
  314. l2 := reflect.ValueOf(list)
  315. l := l2.Len()
  316. var dest []any
  317. var item any
  318. for i := 0; i < l; i++ {
  319. item = l2.Index(i).Interface()
  320. if !inList(dest, item) {
  321. dest = append(dest, item)
  322. }
  323. }
  324. return dest, nil
  325. default:
  326. return nil, fmt.Errorf("cannot find uniq on type %s", tp)
  327. }
  328. }
  329. // inList checks if a value is present in a list.
  330. // It uses deep equality comparison to check for matches.
  331. // Returns true if the value is found, false otherwise.
  332. func inList(haystack []any, needle any) bool {
  333. for _, h := range haystack {
  334. if reflect.DeepEqual(needle, h) {
  335. return true
  336. }
  337. }
  338. return false
  339. }
  340. // without returns a new list with all occurrences of the specified values removed.
  341. // This function will panic if the first argument is not a slice or array.
  342. func without(list any, omit ...any) []any {
  343. l, err := mustWithout(list, omit...)
  344. if err != nil {
  345. panic(err)
  346. }
  347. return l
  348. }
  349. // mustWithout is the implementation of without that returns an error instead of panicking.
  350. // It returns a new list with all occurrences of the specified values removed.
  351. func mustWithout(list any, omit ...any) ([]any, error) {
  352. tp := reflect.TypeOf(list).Kind()
  353. switch tp {
  354. case reflect.Slice, reflect.Array:
  355. l2 := reflect.ValueOf(list)
  356. l := l2.Len()
  357. res := []any{}
  358. var item any
  359. for i := 0; i < l; i++ {
  360. item = l2.Index(i).Interface()
  361. if !inList(omit, item) {
  362. res = append(res, item)
  363. }
  364. }
  365. return res, nil
  366. default:
  367. return nil, fmt.Errorf("cannot find without on type %s", tp)
  368. }
  369. }
  370. // has checks if a value is present in a list.
  371. // Returns true if the value is found, false otherwise.
  372. // This function will panic if the second argument is not a slice or array.
  373. func has(needle any, haystack any) bool {
  374. l, err := mustHas(needle, haystack)
  375. if err != nil {
  376. panic(err)
  377. }
  378. return l
  379. }
  380. // mustHas is the implementation of has that returns an error instead of panicking.
  381. // It checks if a value is present in a list.
  382. func mustHas(needle any, haystack any) (bool, error) {
  383. if haystack == nil {
  384. return false, nil
  385. }
  386. tp := reflect.TypeOf(haystack).Kind()
  387. switch tp {
  388. case reflect.Slice, reflect.Array:
  389. l2 := reflect.ValueOf(haystack)
  390. var item any
  391. l := l2.Len()
  392. for i := 0; i < l; i++ {
  393. item = l2.Index(i).Interface()
  394. if reflect.DeepEqual(needle, item) {
  395. return true, nil
  396. }
  397. }
  398. return false, nil
  399. default:
  400. return false, fmt.Errorf("cannot find has on type %s", tp)
  401. }
  402. }
  403. // slice extracts a portion of a list based on the provided indices.
  404. // Usage examples:
  405. // $list := [1, 2, 3, 4, 5]
  406. // slice $list -> list[0:5] = list[:]
  407. // slice $list 0 3 -> list[0:3] = list[:3]
  408. // slice $list 3 5 -> list[3:5]
  409. // slice $list 3 -> list[3:5] = list[3:]
  410. //
  411. // This function will panic if the first argument is not a slice or array.
  412. func slice(list any, indices ...any) any {
  413. l, err := mustSlice(list, indices...)
  414. if err != nil {
  415. panic(err)
  416. }
  417. return l
  418. }
  419. // mustSlice is the implementation of slice that returns an error instead of panicking.
  420. // It extracts a portion of a list based on the provided indices.
  421. func mustSlice(list any, indices ...any) (any, error) {
  422. tp := reflect.TypeOf(list).Kind()
  423. switch tp {
  424. case reflect.Slice, reflect.Array:
  425. l2 := reflect.ValueOf(list)
  426. l := l2.Len()
  427. if l == 0 {
  428. return nil, nil
  429. }
  430. // Determine start and end indices
  431. var start, end int
  432. if len(indices) > 0 {
  433. start = toInt(indices[0])
  434. }
  435. if len(indices) < 2 {
  436. end = l
  437. } else {
  438. end = toInt(indices[1])
  439. }
  440. return l2.Slice(start, end).Interface(), nil
  441. default:
  442. return nil, fmt.Errorf("list should be type of slice or array but %s", tp)
  443. }
  444. }
  445. // concat combines multiple lists into a single list.
  446. // It takes any number of lists and returns a new list containing all elements.
  447. // This function will panic if any argument is not a slice or array.
  448. func concat(lists ...any) any {
  449. var res []any
  450. for _, list := range lists {
  451. tp := reflect.TypeOf(list).Kind()
  452. switch tp {
  453. case reflect.Slice, reflect.Array:
  454. l2 := reflect.ValueOf(list)
  455. for i := 0; i < l2.Len(); i++ {
  456. res = append(res, l2.Index(i).Interface())
  457. }
  458. default:
  459. panic(fmt.Sprintf("cannot concat type %s as list", tp))
  460. }
  461. }
  462. return res
  463. }