util.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. package jmespath
  2. import (
  3. "errors"
  4. "reflect"
  5. )
  6. // IsFalse determines if an object is false based on the JMESPath spec.
  7. // JMESPath defines false values to be any of:
  8. // - An empty string array, or hash.
  9. // - The boolean value false.
  10. // - nil
  11. func isFalse(value interface{}) bool {
  12. switch v := value.(type) {
  13. case bool:
  14. return !v
  15. case []interface{}:
  16. return len(v) == 0
  17. case map[string]interface{}:
  18. return len(v) == 0
  19. case string:
  20. return len(v) == 0
  21. case nil:
  22. return true
  23. }
  24. // Try the reflection cases before returning false.
  25. rv := reflect.ValueOf(value)
  26. switch rv.Kind() {
  27. case reflect.Struct:
  28. // A struct type will never be false, even if
  29. // all of its values are the zero type.
  30. return false
  31. case reflect.Slice, reflect.Map:
  32. return rv.Len() == 0
  33. case reflect.Ptr:
  34. if rv.IsNil() {
  35. return true
  36. }
  37. // If it's a pointer type, we'll try to deref the pointer
  38. // and evaluate the pointer value for isFalse.
  39. element := rv.Elem()
  40. return isFalse(element.Interface())
  41. }
  42. return false
  43. }
  44. // ObjsEqual is a generic object equality check.
  45. // It will take two arbitrary objects and recursively determine
  46. // if they are equal.
  47. func objsEqual(left interface{}, right interface{}) bool {
  48. return reflect.DeepEqual(left, right)
  49. }
  50. // SliceParam refers to a single part of a slice.
  51. // A slice consists of a start, a stop, and a step, similar to
  52. // python slices.
  53. type sliceParam struct {
  54. N int
  55. Specified bool
  56. }
  57. // Slice supports [start:stop:step] style slicing that's supported in JMESPath.
  58. func slice(slice []interface{}, parts []sliceParam) ([]interface{}, error) {
  59. computed, err := computeSliceParams(len(slice), parts)
  60. if err != nil {
  61. return nil, err
  62. }
  63. start, stop, step := computed[0], computed[1], computed[2]
  64. result := []interface{}{}
  65. if step > 0 {
  66. for i := start; i < stop; i += step {
  67. result = append(result, slice[i])
  68. }
  69. } else {
  70. for i := start; i > stop; i += step {
  71. result = append(result, slice[i])
  72. }
  73. }
  74. return result, nil
  75. }
  76. func computeSliceParams(length int, parts []sliceParam) ([]int, error) {
  77. var start, stop, step int
  78. if !parts[2].Specified {
  79. step = 1
  80. } else if parts[2].N == 0 {
  81. return nil, errors.New("Invalid slice, step cannot be 0")
  82. } else {
  83. step = parts[2].N
  84. }
  85. var stepValueNegative bool
  86. if step < 0 {
  87. stepValueNegative = true
  88. } else {
  89. stepValueNegative = false
  90. }
  91. if !parts[0].Specified {
  92. if stepValueNegative {
  93. start = length - 1
  94. } else {
  95. start = 0
  96. }
  97. } else {
  98. start = capSlice(length, parts[0].N, step)
  99. }
  100. if !parts[1].Specified {
  101. if stepValueNegative {
  102. stop = -1
  103. } else {
  104. stop = length
  105. }
  106. } else {
  107. stop = capSlice(length, parts[1].N, step)
  108. }
  109. return []int{start, stop, step}, nil
  110. }
  111. func capSlice(length int, actual int, step int) int {
  112. if actual < 0 {
  113. actual += length
  114. if actual < 0 {
  115. if step < 0 {
  116. actual = -1
  117. } else {
  118. actual = 0
  119. }
  120. }
  121. } else if actual >= length {
  122. if step < 0 {
  123. actual = length - 1
  124. } else {
  125. actual = length
  126. }
  127. }
  128. return actual
  129. }
  130. // ToArrayNum converts an empty interface type to a slice of float64.
  131. // If any element in the array cannot be converted, then nil is returned
  132. // along with a second value of false.
  133. func toArrayNum(data interface{}) ([]float64, bool) {
  134. // Is there a better way to do this with reflect?
  135. if d, ok := data.([]interface{}); ok {
  136. result := make([]float64, len(d))
  137. for i, el := range d {
  138. item, ok := el.(float64)
  139. if !ok {
  140. return nil, false
  141. }
  142. result[i] = item
  143. }
  144. return result, true
  145. }
  146. return nil, false
  147. }
  148. // ToArrayStr converts an empty interface type to a slice of strings.
  149. // If any element in the array cannot be converted, then nil is returned
  150. // along with a second value of false. If the input data could be entirely
  151. // converted, then the converted data, along with a second value of true,
  152. // will be returned.
  153. func toArrayStr(data interface{}) ([]string, bool) {
  154. // Is there a better way to do this with reflect?
  155. if d, ok := data.([]interface{}); ok {
  156. result := make([]string, len(d))
  157. for i, el := range d {
  158. item, ok := el.(string)
  159. if !ok {
  160. return nil, false
  161. }
  162. result[i] = item
  163. }
  164. return result, true
  165. }
  166. return nil, false
  167. }
  168. func isSliceType(v interface{}) bool {
  169. if v == nil {
  170. return false
  171. }
  172. return reflect.TypeOf(v).Kind() == reflect.Slice
  173. }