]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blame_incremental - vendor/github.com/jmespath/go-jmespath/functions.go
Merge branch 'fix_read_test' of github.com:alexandreFre/terraform-provider-statuscake
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / jmespath / go-jmespath / functions.go
... / ...
CommitLineData
1package jmespath
2
3import (
4 "encoding/json"
5 "errors"
6 "fmt"
7 "math"
8 "reflect"
9 "sort"
10 "strconv"
11 "strings"
12 "unicode/utf8"
13)
14
15type jpFunction func(arguments []interface{}) (interface{}, error)
16
17type jpType string
18
19const (
20 jpUnknown jpType = "unknown"
21 jpNumber jpType = "number"
22 jpString jpType = "string"
23 jpArray jpType = "array"
24 jpObject jpType = "object"
25 jpArrayNumber jpType = "array[number]"
26 jpArrayString jpType = "array[string]"
27 jpExpref jpType = "expref"
28 jpAny jpType = "any"
29)
30
31type functionEntry struct {
32 name string
33 arguments []argSpec
34 handler jpFunction
35 hasExpRef bool
36}
37
38type argSpec struct {
39 types []jpType
40 variadic bool
41}
42
43type byExprString struct {
44 intr *treeInterpreter
45 node ASTNode
46 items []interface{}
47 hasError bool
48}
49
50func (a *byExprString) Len() int {
51 return len(a.items)
52}
53func (a *byExprString) Swap(i, j int) {
54 a.items[i], a.items[j] = a.items[j], a.items[i]
55}
56func (a *byExprString) Less(i, j int) bool {
57 first, err := a.intr.Execute(a.node, a.items[i])
58 if err != nil {
59 a.hasError = true
60 // Return a dummy value.
61 return true
62 }
63 ith, ok := first.(string)
64 if !ok {
65 a.hasError = true
66 return true
67 }
68 second, err := a.intr.Execute(a.node, a.items[j])
69 if err != nil {
70 a.hasError = true
71 // Return a dummy value.
72 return true
73 }
74 jth, ok := second.(string)
75 if !ok {
76 a.hasError = true
77 return true
78 }
79 return ith < jth
80}
81
82type byExprFloat struct {
83 intr *treeInterpreter
84 node ASTNode
85 items []interface{}
86 hasError bool
87}
88
89func (a *byExprFloat) Len() int {
90 return len(a.items)
91}
92func (a *byExprFloat) Swap(i, j int) {
93 a.items[i], a.items[j] = a.items[j], a.items[i]
94}
95func (a *byExprFloat) Less(i, j int) bool {
96 first, err := a.intr.Execute(a.node, a.items[i])
97 if err != nil {
98 a.hasError = true
99 // Return a dummy value.
100 return true
101 }
102 ith, ok := first.(float64)
103 if !ok {
104 a.hasError = true
105 return true
106 }
107 second, err := a.intr.Execute(a.node, a.items[j])
108 if err != nil {
109 a.hasError = true
110 // Return a dummy value.
111 return true
112 }
113 jth, ok := second.(float64)
114 if !ok {
115 a.hasError = true
116 return true
117 }
118 return ith < jth
119}
120
121type functionCaller struct {
122 functionTable map[string]functionEntry
123}
124
125func newFunctionCaller() *functionCaller {
126 caller := &functionCaller{}
127 caller.functionTable = map[string]functionEntry{
128 "length": {
129 name: "length",
130 arguments: []argSpec{
131 {types: []jpType{jpString, jpArray, jpObject}},
132 },
133 handler: jpfLength,
134 },
135 "starts_with": {
136 name: "starts_with",
137 arguments: []argSpec{
138 {types: []jpType{jpString}},
139 {types: []jpType{jpString}},
140 },
141 handler: jpfStartsWith,
142 },
143 "abs": {
144 name: "abs",
145 arguments: []argSpec{
146 {types: []jpType{jpNumber}},
147 },
148 handler: jpfAbs,
149 },
150 "avg": {
151 name: "avg",
152 arguments: []argSpec{
153 {types: []jpType{jpArrayNumber}},
154 },
155 handler: jpfAvg,
156 },
157 "ceil": {
158 name: "ceil",
159 arguments: []argSpec{
160 {types: []jpType{jpNumber}},
161 },
162 handler: jpfCeil,
163 },
164 "contains": {
165 name: "contains",
166 arguments: []argSpec{
167 {types: []jpType{jpArray, jpString}},
168 {types: []jpType{jpAny}},
169 },
170 handler: jpfContains,
171 },
172 "ends_with": {
173 name: "ends_with",
174 arguments: []argSpec{
175 {types: []jpType{jpString}},
176 {types: []jpType{jpString}},
177 },
178 handler: jpfEndsWith,
179 },
180 "floor": {
181 name: "floor",
182 arguments: []argSpec{
183 {types: []jpType{jpNumber}},
184 },
185 handler: jpfFloor,
186 },
187 "map": {
188 name: "amp",
189 arguments: []argSpec{
190 {types: []jpType{jpExpref}},
191 {types: []jpType{jpArray}},
192 },
193 handler: jpfMap,
194 hasExpRef: true,
195 },
196 "max": {
197 name: "max",
198 arguments: []argSpec{
199 {types: []jpType{jpArrayNumber, jpArrayString}},
200 },
201 handler: jpfMax,
202 },
203 "merge": {
204 name: "merge",
205 arguments: []argSpec{
206 {types: []jpType{jpObject}, variadic: true},
207 },
208 handler: jpfMerge,
209 },
210 "max_by": {
211 name: "max_by",
212 arguments: []argSpec{
213 {types: []jpType{jpArray}},
214 {types: []jpType{jpExpref}},
215 },
216 handler: jpfMaxBy,
217 hasExpRef: true,
218 },
219 "sum": {
220 name: "sum",
221 arguments: []argSpec{
222 {types: []jpType{jpArrayNumber}},
223 },
224 handler: jpfSum,
225 },
226 "min": {
227 name: "min",
228 arguments: []argSpec{
229 {types: []jpType{jpArrayNumber, jpArrayString}},
230 },
231 handler: jpfMin,
232 },
233 "min_by": {
234 name: "min_by",
235 arguments: []argSpec{
236 {types: []jpType{jpArray}},
237 {types: []jpType{jpExpref}},
238 },
239 handler: jpfMinBy,
240 hasExpRef: true,
241 },
242 "type": {
243 name: "type",
244 arguments: []argSpec{
245 {types: []jpType{jpAny}},
246 },
247 handler: jpfType,
248 },
249 "keys": {
250 name: "keys",
251 arguments: []argSpec{
252 {types: []jpType{jpObject}},
253 },
254 handler: jpfKeys,
255 },
256 "values": {
257 name: "values",
258 arguments: []argSpec{
259 {types: []jpType{jpObject}},
260 },
261 handler: jpfValues,
262 },
263 "sort": {
264 name: "sort",
265 arguments: []argSpec{
266 {types: []jpType{jpArrayString, jpArrayNumber}},
267 },
268 handler: jpfSort,
269 },
270 "sort_by": {
271 name: "sort_by",
272 arguments: []argSpec{
273 {types: []jpType{jpArray}},
274 {types: []jpType{jpExpref}},
275 },
276 handler: jpfSortBy,
277 hasExpRef: true,
278 },
279 "join": {
280 name: "join",
281 arguments: []argSpec{
282 {types: []jpType{jpString}},
283 {types: []jpType{jpArrayString}},
284 },
285 handler: jpfJoin,
286 },
287 "reverse": {
288 name: "reverse",
289 arguments: []argSpec{
290 {types: []jpType{jpArray, jpString}},
291 },
292 handler: jpfReverse,
293 },
294 "to_array": {
295 name: "to_array",
296 arguments: []argSpec{
297 {types: []jpType{jpAny}},
298 },
299 handler: jpfToArray,
300 },
301 "to_string": {
302 name: "to_string",
303 arguments: []argSpec{
304 {types: []jpType{jpAny}},
305 },
306 handler: jpfToString,
307 },
308 "to_number": {
309 name: "to_number",
310 arguments: []argSpec{
311 {types: []jpType{jpAny}},
312 },
313 handler: jpfToNumber,
314 },
315 "not_null": {
316 name: "not_null",
317 arguments: []argSpec{
318 {types: []jpType{jpAny}, variadic: true},
319 },
320 handler: jpfNotNull,
321 },
322 }
323 return caller
324}
325
326func (e *functionEntry) resolveArgs(arguments []interface{}) ([]interface{}, error) {
327 if len(e.arguments) == 0 {
328 return arguments, nil
329 }
330 if !e.arguments[len(e.arguments)-1].variadic {
331 if len(e.arguments) != len(arguments) {
332 return nil, errors.New("incorrect number of args")
333 }
334 for i, spec := range e.arguments {
335 userArg := arguments[i]
336 err := spec.typeCheck(userArg)
337 if err != nil {
338 return nil, err
339 }
340 }
341 return arguments, nil
342 }
343 if len(arguments) < len(e.arguments) {
344 return nil, errors.New("Invalid arity.")
345 }
346 return arguments, nil
347}
348
349func (a *argSpec) typeCheck(arg interface{}) error {
350 for _, t := range a.types {
351 switch t {
352 case jpNumber:
353 if _, ok := arg.(float64); ok {
354 return nil
355 }
356 case jpString:
357 if _, ok := arg.(string); ok {
358 return nil
359 }
360 case jpArray:
361 if isSliceType(arg) {
362 return nil
363 }
364 case jpObject:
365 if _, ok := arg.(map[string]interface{}); ok {
366 return nil
367 }
368 case jpArrayNumber:
369 if _, ok := toArrayNum(arg); ok {
370 return nil
371 }
372 case jpArrayString:
373 if _, ok := toArrayStr(arg); ok {
374 return nil
375 }
376 case jpAny:
377 return nil
378 case jpExpref:
379 if _, ok := arg.(expRef); ok {
380 return nil
381 }
382 }
383 }
384 return fmt.Errorf("Invalid type for: %v, expected: %#v", arg, a.types)
385}
386
387func (f *functionCaller) CallFunction(name string, arguments []interface{}, intr *treeInterpreter) (interface{}, error) {
388 entry, ok := f.functionTable[name]
389 if !ok {
390 return nil, errors.New("unknown function: " + name)
391 }
392 resolvedArgs, err := entry.resolveArgs(arguments)
393 if err != nil {
394 return nil, err
395 }
396 if entry.hasExpRef {
397 var extra []interface{}
398 extra = append(extra, intr)
399 resolvedArgs = append(extra, resolvedArgs...)
400 }
401 return entry.handler(resolvedArgs)
402}
403
404func jpfAbs(arguments []interface{}) (interface{}, error) {
405 num := arguments[0].(float64)
406 return math.Abs(num), nil
407}
408
409func jpfLength(arguments []interface{}) (interface{}, error) {
410 arg := arguments[0]
411 if c, ok := arg.(string); ok {
412 return float64(utf8.RuneCountInString(c)), nil
413 } else if isSliceType(arg) {
414 v := reflect.ValueOf(arg)
415 return float64(v.Len()), nil
416 } else if c, ok := arg.(map[string]interface{}); ok {
417 return float64(len(c)), nil
418 }
419 return nil, errors.New("could not compute length()")
420}
421
422func jpfStartsWith(arguments []interface{}) (interface{}, error) {
423 search := arguments[0].(string)
424 prefix := arguments[1].(string)
425 return strings.HasPrefix(search, prefix), nil
426}
427
428func jpfAvg(arguments []interface{}) (interface{}, error) {
429 // We've already type checked the value so we can safely use
430 // type assertions.
431 args := arguments[0].([]interface{})
432 length := float64(len(args))
433 numerator := 0.0
434 for _, n := range args {
435 numerator += n.(float64)
436 }
437 return numerator / length, nil
438}
439func jpfCeil(arguments []interface{}) (interface{}, error) {
440 val := arguments[0].(float64)
441 return math.Ceil(val), nil
442}
443func jpfContains(arguments []interface{}) (interface{}, error) {
444 search := arguments[0]
445 el := arguments[1]
446 if searchStr, ok := search.(string); ok {
447 if elStr, ok := el.(string); ok {
448 return strings.Index(searchStr, elStr) != -1, nil
449 }
450 return false, nil
451 }
452 // Otherwise this is a generic contains for []interface{}
453 general := search.([]interface{})
454 for _, item := range general {
455 if item == el {
456 return true, nil
457 }
458 }
459 return false, nil
460}
461func jpfEndsWith(arguments []interface{}) (interface{}, error) {
462 search := arguments[0].(string)
463 suffix := arguments[1].(string)
464 return strings.HasSuffix(search, suffix), nil
465}
466func jpfFloor(arguments []interface{}) (interface{}, error) {
467 val := arguments[0].(float64)
468 return math.Floor(val), nil
469}
470func jpfMap(arguments []interface{}) (interface{}, error) {
471 intr := arguments[0].(*treeInterpreter)
472 exp := arguments[1].(expRef)
473 node := exp.ref
474 arr := arguments[2].([]interface{})
475 mapped := make([]interface{}, 0, len(arr))
476 for _, value := range arr {
477 current, err := intr.Execute(node, value)
478 if err != nil {
479 return nil, err
480 }
481 mapped = append(mapped, current)
482 }
483 return mapped, nil
484}
485func jpfMax(arguments []interface{}) (interface{}, error) {
486 if items, ok := toArrayNum(arguments[0]); ok {
487 if len(items) == 0 {
488 return nil, nil
489 }
490 if len(items) == 1 {
491 return items[0], nil
492 }
493 best := items[0]
494 for _, item := range items[1:] {
495 if item > best {
496 best = item
497 }
498 }
499 return best, nil
500 }
501 // Otherwise we're dealing with a max() of strings.
502 items, _ := toArrayStr(arguments[0])
503 if len(items) == 0 {
504 return nil, nil
505 }
506 if len(items) == 1 {
507 return items[0], nil
508 }
509 best := items[0]
510 for _, item := range items[1:] {
511 if item > best {
512 best = item
513 }
514 }
515 return best, nil
516}
517func jpfMerge(arguments []interface{}) (interface{}, error) {
518 final := make(map[string]interface{})
519 for _, m := range arguments {
520 mapped := m.(map[string]interface{})
521 for key, value := range mapped {
522 final[key] = value
523 }
524 }
525 return final, nil
526}
527func jpfMaxBy(arguments []interface{}) (interface{}, error) {
528 intr := arguments[0].(*treeInterpreter)
529 arr := arguments[1].([]interface{})
530 exp := arguments[2].(expRef)
531 node := exp.ref
532 if len(arr) == 0 {
533 return nil, nil
534 } else if len(arr) == 1 {
535 return arr[0], nil
536 }
537 start, err := intr.Execute(node, arr[0])
538 if err != nil {
539 return nil, err
540 }
541 switch t := start.(type) {
542 case float64:
543 bestVal := t
544 bestItem := arr[0]
545 for _, item := range arr[1:] {
546 result, err := intr.Execute(node, item)
547 if err != nil {
548 return nil, err
549 }
550 current, ok := result.(float64)
551 if !ok {
552 return nil, errors.New("invalid type, must be number")
553 }
554 if current > bestVal {
555 bestVal = current
556 bestItem = item
557 }
558 }
559 return bestItem, nil
560 case string:
561 bestVal := t
562 bestItem := arr[0]
563 for _, item := range arr[1:] {
564 result, err := intr.Execute(node, item)
565 if err != nil {
566 return nil, err
567 }
568 current, ok := result.(string)
569 if !ok {
570 return nil, errors.New("invalid type, must be string")
571 }
572 if current > bestVal {
573 bestVal = current
574 bestItem = item
575 }
576 }
577 return bestItem, nil
578 default:
579 return nil, errors.New("invalid type, must be number of string")
580 }
581}
582func jpfSum(arguments []interface{}) (interface{}, error) {
583 items, _ := toArrayNum(arguments[0])
584 sum := 0.0
585 for _, item := range items {
586 sum += item
587 }
588 return sum, nil
589}
590
591func jpfMin(arguments []interface{}) (interface{}, error) {
592 if items, ok := toArrayNum(arguments[0]); ok {
593 if len(items) == 0 {
594 return nil, nil
595 }
596 if len(items) == 1 {
597 return items[0], nil
598 }
599 best := items[0]
600 for _, item := range items[1:] {
601 if item < best {
602 best = item
603 }
604 }
605 return best, nil
606 }
607 items, _ := toArrayStr(arguments[0])
608 if len(items) == 0 {
609 return nil, nil
610 }
611 if len(items) == 1 {
612 return items[0], nil
613 }
614 best := items[0]
615 for _, item := range items[1:] {
616 if item < best {
617 best = item
618 }
619 }
620 return best, nil
621}
622
623func jpfMinBy(arguments []interface{}) (interface{}, error) {
624 intr := arguments[0].(*treeInterpreter)
625 arr := arguments[1].([]interface{})
626 exp := arguments[2].(expRef)
627 node := exp.ref
628 if len(arr) == 0 {
629 return nil, nil
630 } else if len(arr) == 1 {
631 return arr[0], nil
632 }
633 start, err := intr.Execute(node, arr[0])
634 if err != nil {
635 return nil, err
636 }
637 if t, ok := start.(float64); ok {
638 bestVal := t
639 bestItem := arr[0]
640 for _, item := range arr[1:] {
641 result, err := intr.Execute(node, item)
642 if err != nil {
643 return nil, err
644 }
645 current, ok := result.(float64)
646 if !ok {
647 return nil, errors.New("invalid type, must be number")
648 }
649 if current < bestVal {
650 bestVal = current
651 bestItem = item
652 }
653 }
654 return bestItem, nil
655 } else if t, ok := start.(string); ok {
656 bestVal := t
657 bestItem := arr[0]
658 for _, item := range arr[1:] {
659 result, err := intr.Execute(node, item)
660 if err != nil {
661 return nil, err
662 }
663 current, ok := result.(string)
664 if !ok {
665 return nil, errors.New("invalid type, must be string")
666 }
667 if current < bestVal {
668 bestVal = current
669 bestItem = item
670 }
671 }
672 return bestItem, nil
673 } else {
674 return nil, errors.New("invalid type, must be number of string")
675 }
676}
677func jpfType(arguments []interface{}) (interface{}, error) {
678 arg := arguments[0]
679 if _, ok := arg.(float64); ok {
680 return "number", nil
681 }
682 if _, ok := arg.(string); ok {
683 return "string", nil
684 }
685 if _, ok := arg.([]interface{}); ok {
686 return "array", nil
687 }
688 if _, ok := arg.(map[string]interface{}); ok {
689 return "object", nil
690 }
691 if arg == nil {
692 return "null", nil
693 }
694 if arg == true || arg == false {
695 return "boolean", nil
696 }
697 return nil, errors.New("unknown type")
698}
699func jpfKeys(arguments []interface{}) (interface{}, error) {
700 arg := arguments[0].(map[string]interface{})
701 collected := make([]interface{}, 0, len(arg))
702 for key := range arg {
703 collected = append(collected, key)
704 }
705 return collected, nil
706}
707func jpfValues(arguments []interface{}) (interface{}, error) {
708 arg := arguments[0].(map[string]interface{})
709 collected := make([]interface{}, 0, len(arg))
710 for _, value := range arg {
711 collected = append(collected, value)
712 }
713 return collected, nil
714}
715func jpfSort(arguments []interface{}) (interface{}, error) {
716 if items, ok := toArrayNum(arguments[0]); ok {
717 d := sort.Float64Slice(items)
718 sort.Stable(d)
719 final := make([]interface{}, len(d))
720 for i, val := range d {
721 final[i] = val
722 }
723 return final, nil
724 }
725 // Otherwise we're dealing with sort()'ing strings.
726 items, _ := toArrayStr(arguments[0])
727 d := sort.StringSlice(items)
728 sort.Stable(d)
729 final := make([]interface{}, len(d))
730 for i, val := range d {
731 final[i] = val
732 }
733 return final, nil
734}
735func jpfSortBy(arguments []interface{}) (interface{}, error) {
736 intr := arguments[0].(*treeInterpreter)
737 arr := arguments[1].([]interface{})
738 exp := arguments[2].(expRef)
739 node := exp.ref
740 if len(arr) == 0 {
741 return arr, nil
742 } else if len(arr) == 1 {
743 return arr, nil
744 }
745 start, err := intr.Execute(node, arr[0])
746 if err != nil {
747 return nil, err
748 }
749 if _, ok := start.(float64); ok {
750 sortable := &byExprFloat{intr, node, arr, false}
751 sort.Stable(sortable)
752 if sortable.hasError {
753 return nil, errors.New("error in sort_by comparison")
754 }
755 return arr, nil
756 } else if _, ok := start.(string); ok {
757 sortable := &byExprString{intr, node, arr, false}
758 sort.Stable(sortable)
759 if sortable.hasError {
760 return nil, errors.New("error in sort_by comparison")
761 }
762 return arr, nil
763 } else {
764 return nil, errors.New("invalid type, must be number of string")
765 }
766}
767func jpfJoin(arguments []interface{}) (interface{}, error) {
768 sep := arguments[0].(string)
769 // We can't just do arguments[1].([]string), we have to
770 // manually convert each item to a string.
771 arrayStr := []string{}
772 for _, item := range arguments[1].([]interface{}) {
773 arrayStr = append(arrayStr, item.(string))
774 }
775 return strings.Join(arrayStr, sep), nil
776}
777func jpfReverse(arguments []interface{}) (interface{}, error) {
778 if s, ok := arguments[0].(string); ok {
779 r := []rune(s)
780 for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
781 r[i], r[j] = r[j], r[i]
782 }
783 return string(r), nil
784 }
785 items := arguments[0].([]interface{})
786 length := len(items)
787 reversed := make([]interface{}, length)
788 for i, item := range items {
789 reversed[length-(i+1)] = item
790 }
791 return reversed, nil
792}
793func jpfToArray(arguments []interface{}) (interface{}, error) {
794 if _, ok := arguments[0].([]interface{}); ok {
795 return arguments[0], nil
796 }
797 return arguments[:1:1], nil
798}
799func jpfToString(arguments []interface{}) (interface{}, error) {
800 if v, ok := arguments[0].(string); ok {
801 return v, nil
802 }
803 result, err := json.Marshal(arguments[0])
804 if err != nil {
805 return nil, err
806 }
807 return string(result), nil
808}
809func jpfToNumber(arguments []interface{}) (interface{}, error) {
810 arg := arguments[0]
811 if v, ok := arg.(float64); ok {
812 return v, nil
813 }
814 if v, ok := arg.(string); ok {
815 conv, err := strconv.ParseFloat(v, 64)
816 if err != nil {
817 return nil, nil
818 }
819 return conv, nil
820 }
821 if _, ok := arg.([]interface{}); ok {
822 return nil, nil
823 }
824 if _, ok := arg.(map[string]interface{}); ok {
825 return nil, nil
826 }
827 if arg == nil {
828 return nil, nil
829 }
830 if arg == true || arg == false {
831 return nil, nil
832 }
833 return nil, errors.New("unknown type")
834}
835func jpfNotNull(arguments []interface{}) (interface{}, error) {
836 for _, arg := range arguments {
837 if arg != nil {
838 return arg, nil
839 }
840 }
841 return nil, nil
842}