snapshot of https://github.com/cortezaproject/corteza.git (2024.9.x, 2026-09-18; blobs > 131072B omitted)
Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s

This commit is contained in:
upstream-mirror
2026-09-18 01:22:23 +05:00
commit 7e385fc126
8391 changed files with 1766236 additions and 0 deletions

30
server/vendor/github.com/PaesslerAG/gval/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,30 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
coverage.out
manual_test.go
*.out
*.err
.vscode

12
server/vendor/github.com/PaesslerAG/gval/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,12 @@
language: go
before_install:
- go get golang.org/x/tools/cmd/cover
- go get github.com/mattn/goveralls
script:
- go test -bench=. -benchmem -timeout 9m -coverprofile coverage.out
- $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci -repotoken=$COVERALLS_TOKEN
- go test -bench=Random -benchtime 3m -timeout 9m -benchmem -coverprofile coverage.out
go: "1.15"

12
server/vendor/github.com/PaesslerAG/gval/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,12 @@
Copyright (c) 2017, Paessler AG <support@paessler.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

163
server/vendor/github.com/PaesslerAG/gval/README.md generated vendored Normal file
View File

@@ -0,0 +1,163 @@
# Gval
[![Go Reference](https://pkg.go.dev/badge/github.com/PaesslerAG/gval.svg)](https://pkg.go.dev/github.com/PaesslerAG/gval)
[![Build Status](https://api.travis-ci.org/PaesslerAG/gval.svg?branch=master)](https://travis-ci.org/PaesslerAG/gval)
[![Coverage Status](https://coveralls.io/repos/github/PaesslerAG/gval/badge.svg?branch=master)](https://coveralls.io/github/PaesslerAG/gval?branch=master)
[![Go Report Card](https://goreportcard.com/badge/github.com/PaesslerAG/gval)](https://goreportcard.com/report/github.com/PaesslerAG/gval)
Gval (Go eVALuate) provides support for evaluating arbitrary expressions, in particular Go-like expressions.
![gopher](./prtg-batmin-gopher.png)
## Evaluate
Gval can evaluate expressions with parameters, arimethetic, logical, and string operations:
- basic expression: [10 > 0](https://pkg.go.dev/github.com/PaesslerAG/gval/#example-Evaluate-Basic)
- parameterized expression: [foo > 0](https://pkg.go.dev/github.com/PaesslerAG/gval/#example-Evaluate-Parameter)
- nested parameterized expression: [foo.bar > 0](https://pkg.go.dev/github.com/PaesslerAG/gval/#example-Evaluate-NestedParameter)
- arithmetic expression: [(requests_made * requests_succeeded / 100) >= 90](https://pkg.go.dev/github.com/PaesslerAG/gval/#example-Evaluate-Arithmetic)
- string expression: [http_response_body == "service is ok"](https://pkg.go.dev/github.com/PaesslerAG/gval/#example-Evaluate-String)
- float64 expression: [(mem_used / total_mem) * 100](https://pkg.go.dev/github.com/PaesslerAG/gval/#example-Evaluate-Float64)
It can easily be extended with custom functions or operators:
- custom date comparator: [date(\`2014-01-02\`) > date(\`2014-01-01 23:59:59\`)](https://pkg.go.dev/github.com/PaesslerAG/gval/#example-Evaluate-DateComparison)
- string length: [strlen("someReallyLongInputString") <= 16](https://pkg.go.dev/github.com/PaesslerAG/gval/#example-Evaluate-Strlen)
You can parse gval.Expressions once and re-use them multiple times. Parsing is the compute-intensive phase of the process, so if you intend to use the same expression with different parameters, just parse it once:
- [Parsing and Evaluation](https://pkg.go.dev/github.com/PaesslerAG/gval/#example-Evaluable)
The normal Go-standard order of operators is respected. When writing an expression, be sure that you either order the operators correctly, or use parentheses to clarify which portions of an expression should be run first.
Strings, numbers, and booleans can be used like in Go:
- [(7 < "47" == true ? "hello world!\n\u263a") + \` more text\`](https://pkg.go.dev/github.com/PaesslerAG/gval/#example-Evaluate-Encoding)
## Parameter
Variables can be accessed via string literals. They can be used for values with string keys if the parameter is a `map[string]interface{}` or `map[interface{}]interface{}` and for fields or methods if the parameter is a struct.
- [foo > 0](https://pkg.go.dev/github.com/PaesslerAG/gval/#example-Evaluate-Parameter)
### Bracket Selector
Map and array elements and Struct Field can be accessed via `[]`.
- [foo[0]](https://pkg.go.dev/github.com/PaesslerAG/gval/#example-Evaluate-Array)
- [foo["b" + "a" + "r"]](https://pkg.go.dev/github.com/PaesslerAG/gval/#example-Evaluate-ExampleEvaluate_ComplexAccessor)
### Dot Selector
A nested variable with a name containing only letters and underscores can be accessed via a dot selector.
- [foo.bar > 0](https://pkg.go.dev/github.com/PaesslerAG/gval/#example-Evaluate-NestedParameter)
### Custom Selector
Parameter names like `response-time` will be interpreted as `response` minus `time`. While gval doesn't support these parameter names directly, you can easily access them via a custom extension like [JSON Path](https://github.com/PaesslerAG/jsonpath):
- [$["response-time"]](https://pkg.go.dev/github.com/PaesslerAG/gval/#example-Evaluate-Jsonpath)
Jsonpath is also suitable for accessing array elements.
### Fields and Methods
If you have structs in your parameters, you can access their fields and methods in the usual way:
- [foo.Hello + foo.World()](https://pkg.go.dev/github.com/PaesslerAG/gval/#example-Evaluate-FlatAccessor)
It also works if the parameter is a struct directly
[Hello + World()](https://pkg.go.dev/github.com/PaesslerAG/gval/#example-Evaluate-Accessor)
or if the fields are nested
[foo.Hello + foo.World()](https://pkg.go.dev/github.com/PaesslerAG/gval/#example-Evaluate-NestedAccessor)
This may be convenient but note that using accessors on strucs makes the expression about four times slower than just using a parameter (consult the benchmarks for more precise measurements on your system). If there are functions you want to use, it's faster (and probably cleaner) to define them as functions (see the Evaluate section). These approaches use no reflection, and are designed to be fast and clean.
## Default Language
The default language is in serveral sub languages like text, arithmetic or propositional logic defined. See [Godoc](https://pkg.go.dev/github.com/PaesslerAG/gval/#Gval) for details. All sub languages are merged into gval.Full which contains the following elements:
- Modifiers: `+` `-` `/` `*` `&` `|` `^` `**` `%` `>>` `<<`
- Comparators: `>` `>=` `<` `<=` `==` `!=` `=~` `!~`
- Logical ops: `||` `&&`
- Numeric constants, as 64-bit floating point (`12345.678`)
- String constants (double quotes: `"foobar"`)
- Date function 'Date(x)', using any permutation of RFC3339, ISO8601, ruby date, or unix date
- Boolean constants: `true` `false`
- Parentheses to control order of evaluation `(` `)`
- Json Arrays : `[1, 2, "foo"]`
- Json Objects : `{"a":1, "b":2, "c":"foo"}`
- Prefixes: `!` `-` `~`
- Ternary conditional: `?` `:`
- Null coalescence: `??`
## Customize
Gval is completly customizable. Every constant, function or operator can be defined separately and existing expression languages can be reused:
- [foo.Hello + foo.World()](https://pkg.go.dev/github.com/PaesslerAG/gval/#example-Language)
For details see [Godoc](https://pkg.go.dev/github.com/PaesslerAG/gval).
### Implementing custom selector
In a case you want to provide custom logic for selectors you can implement `SelectGVal(ctx context.Context, k string) (interface{}, error)` on your struct.
Function receives next part of the path and can return any type of var that is again evaluated through standard gval procedures.
[Example Custom Selector](https://pkg.go.dev/github.com/PaesslerAG/gval/#example-custom-selector)
### External gval Languages
A list of external libraries for gval. Feel free to add your own library.
- [gvalstrings](https://github.com/generikvault/gvalstrings) parse single quoted strings in gval.
- [jsonpath](https://github.com/PaesslerAG/jsonpath) full support for jsonpath in gval.
## Performance
The library is built with the intention of being quick but has not been aggressively profiled and optimized. For most applications, though, it is completely fine.
If performance is an issue, make sure to create your expression language with all functions, constants and operators only once. Evaluating an expression like gval.Evaluate("expression, const1, func1, func2, ...) creates a new gval.Language everytime it is called and slows execution.
The library comes with a bunch of benchmarks to measure the performance of parsing and evaluating expressions. You can run them with `go test -bench=.`.
For a very rough idea of performance, here are the results from a benchmark run on a Dell Latitude E7470 Win 10 i5-6300U.
``` text
BenchmarkGval/const_evaluation-4 500000000 3.57 ns/op
BenchmarkGval/const_parsing-4 1000000 1144 ns/op
BenchmarkGval/single_parameter_evaluation-4 10000000 165 ns/op
BenchmarkGval/single_parameter_parsing-4 1000000 1648 ns/op
BenchmarkGval/parameter_evaluation-4 5000000 352 ns/op
BenchmarkGval/parameter_parsing-4 500000 2773 ns/op
BenchmarkGval/common_evaluation-4 3000000 434 ns/op
BenchmarkGval/common_parsing-4 300000 4419 ns/op
BenchmarkGval/complex_evaluation-4 100000000 11.6 ns/op
BenchmarkGval/complex_parsing-4 100000 17936 ns/op
BenchmarkGval/literal_evaluation-4 300000000 3.84 ns/op
BenchmarkGval/literal_parsing-4 500000 2559 ns/op
BenchmarkGval/modifier_evaluation-4 500000000 3.54 ns/op
BenchmarkGval/modifier_parsing-4 500000 3755 ns/op
BenchmarkGval/regex_evaluation-4 50000 21347 ns/op
BenchmarkGval/regex_parsing-4 200000 6480 ns/op
BenchmarkGval/constant_regex_evaluation-4 1000000 1000 ns/op
BenchmarkGval/constant_regex_parsing-4 200000 9417 ns/op
BenchmarkGval/accessors_evaluation-4 3000000 417 ns/op
BenchmarkGval/accessors_parsing-4 1000000 1778 ns/op
BenchmarkGval/accessors_method_evaluation-4 1000000 1931 ns/op
BenchmarkGval/accessors_method_parsing-4 1000000 1729 ns/op
BenchmarkGval/accessors_method_parameter_evaluation-4 1000000 2162 ns/op
BenchmarkGval/accessors_method_parameter_parsing-4 500000 2618 ns/op
BenchmarkGval/nested_accessors_evaluation-4 2000000 681 ns/op
BenchmarkGval/nested_accessors_parsing-4 1000000 2115 ns/op
BenchmarkRandom-4 500000 3631 ns/op
ok
```
## API Breaks
Gval is designed with easy expandability in mind and API breaks will be avoided if possible. If API breaks are unavoidable they wil be explicitly stated via an increased major version number.
-------------------------------------
Credits to Reene French for the gophers.

363
server/vendor/github.com/PaesslerAG/gval/evaluable.go generated vendored Normal file
View File

@@ -0,0 +1,363 @@
package gval
import (
"context"
"fmt"
"reflect"
"regexp"
"strconv"
"strings"
)
// Selector allows for custom variable selection from structs
//
// Return value is again handled with variable() until end of the given path
type Selector interface {
SelectGVal(c context.Context, key string) (interface{}, error)
}
// Evaluable evaluates given parameter
type Evaluable func(c context.Context, parameter interface{}) (interface{}, error)
// EvalInt evaluates given parameter to an int
func (e Evaluable) EvalInt(c context.Context, parameter interface{}) (int, error) {
v, err := e(c, parameter)
if err != nil {
return 0, err
}
f, ok := convertToFloat(v)
if !ok {
return 0, fmt.Errorf("expected number but got %v (%T)", v, v)
}
return int(f), nil
}
// EvalFloat64 evaluates given parameter to a float64
func (e Evaluable) EvalFloat64(c context.Context, parameter interface{}) (float64, error) {
v, err := e(c, parameter)
if err != nil {
return 0, err
}
f, ok := convertToFloat(v)
if !ok {
return 0, fmt.Errorf("expected number but got %v (%T)", v, v)
}
return f, nil
}
// EvalBool evaluates given parameter to a bool
func (e Evaluable) EvalBool(c context.Context, parameter interface{}) (bool, error) {
v, err := e(c, parameter)
if err != nil {
return false, err
}
b, ok := convertToBool(v)
if !ok {
return false, fmt.Errorf("expected bool but got %v (%T)", v, v)
}
return b, nil
}
// EvalString evaluates given parameter to a string
func (e Evaluable) EvalString(c context.Context, parameter interface{}) (string, error) {
o, err := e(c, parameter)
if err != nil {
return "", err
}
return fmt.Sprintf("%v", o), nil
}
// Const Evaluable represents given constant
func (*Parser) Const(value interface{}) Evaluable {
return constant(value)
}
//go:noinline
func constant(value interface{}) Evaluable {
return func(c context.Context, v interface{}) (interface{}, error) {
return value, nil
}
}
// Var Evaluable represents value at given path.
// It supports with default language VariableSelector:
//
// map[interface{}]interface{},
// map[string]interface{} and
// []interface{} and via reflect
// struct fields,
// struct methods,
// slices and
// map with int or string key.
func (p *Parser) Var(path ...Evaluable) Evaluable {
if p.selector == nil {
return variable(path)
}
return p.selector(path)
}
// Evaluables is a slice of Evaluable.
type Evaluables []Evaluable
// EvalStrings evaluates given parameter to a string slice
func (evs Evaluables) EvalStrings(c context.Context, parameter interface{}) ([]string, error) {
strs := make([]string, len(evs))
for i, p := range evs {
k, err := p.EvalString(c, parameter)
if err != nil {
return nil, err
}
strs[i] = k
}
return strs, nil
}
func variable(path Evaluables) Evaluable {
return func(c context.Context, v interface{}) (interface{}, error) {
keys, err := path.EvalStrings(c, v)
if err != nil {
return nil, err
}
for i, k := range keys {
switch o := v.(type) {
case Selector:
v, err = o.SelectGVal(c, k)
if err != nil {
return nil, fmt.Errorf("failed to select '%s' on %T: %w", k, o, err)
}
continue
case map[interface{}]interface{}:
v = o[k]
continue
case map[string]interface{}:
v = o[k]
continue
case []interface{}:
if i, err := strconv.Atoi(k); err == nil && i >= 0 && len(o) > i {
v = o[i]
continue
}
default:
var ok bool
v, ok = reflectSelect(k, o)
if !ok {
return nil, fmt.Errorf("unknown parameter %s", strings.Join(keys[:i+1], "."))
}
}
}
return v, nil
}
}
func reflectSelect(key string, value interface{}) (selection interface{}, ok bool) {
vv := reflect.ValueOf(value)
vvElem := resolvePotentialPointer(vv)
switch vvElem.Kind() {
case reflect.Map:
mapKey, ok := reflectConvertTo(vv.Type().Key().Kind(), key)
if !ok {
return nil, false
}
vvElem = vv.MapIndex(reflect.ValueOf(mapKey))
vvElem = resolvePotentialPointer(vvElem)
if vvElem.IsValid() {
return vvElem.Interface(), true
}
// key didn't exist. Check if there is a bound method
method := vv.MethodByName(key)
if method.IsValid() {
return method.Interface(), true
}
case reflect.Slice:
if i, err := strconv.Atoi(key); err == nil && i >= 0 && vv.Len() > i {
vvElem = resolvePotentialPointer(vv.Index(i))
return vvElem.Interface(), true
}
// key not an int. Check if there is a bound method
method := vv.MethodByName(key)
if method.IsValid() {
return method.Interface(), true
}
case reflect.Struct:
field := vvElem.FieldByName(key)
if field.IsValid() {
return field.Interface(), true
}
method := vv.MethodByName(key)
if method.IsValid() {
return method.Interface(), true
}
}
return nil, false
}
func resolvePotentialPointer(value reflect.Value) reflect.Value {
if value.Kind() == reflect.Ptr {
return value.Elem()
}
return value
}
func reflectConvertTo(k reflect.Kind, value string) (interface{}, bool) {
switch k {
case reflect.String:
return value, true
case reflect.Int:
if i, err := strconv.Atoi(value); err == nil {
return i, true
}
}
return nil, false
}
func (*Parser) callFunc(fun function, args ...Evaluable) Evaluable {
return func(c context.Context, v interface{}) (ret interface{}, err error) {
a := make([]interface{}, len(args))
for i, arg := range args {
ai, err := arg(c, v)
if err != nil {
return nil, err
}
a[i] = ai
}
return fun(c, a...)
}
}
func (*Parser) callEvaluable(fullname string, fun Evaluable, args ...Evaluable) Evaluable {
return func(c context.Context, v interface{}) (ret interface{}, err error) {
f, err := fun(c, v)
if err != nil {
return nil, fmt.Errorf("could not call function: %w", err)
}
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("failed to execute function '%s': %s", fullname, r)
ret = nil
}
}()
ff := reflect.ValueOf(f)
if ff.Kind() != reflect.Func {
return nil, fmt.Errorf("could not call '%s' type %T", fullname, f)
}
a := make([]reflect.Value, len(args))
for i := range args {
arg, err := args[i](c, v)
if err != nil {
return nil, err
}
a[i] = reflect.ValueOf(arg)
}
rr := ff.Call(a)
r := make([]interface{}, len(rr))
for i, e := range rr {
r[i] = e.Interface()
}
errorInterface := reflect.TypeOf((*error)(nil)).Elem()
if len(r) > 0 && ff.Type().Out(len(r)-1).Implements(errorInterface) {
if r[len(r)-1] != nil {
err = r[len(r)-1].(error)
}
r = r[0 : len(r)-1]
}
switch len(r) {
case 0:
return err, nil
case 1:
return r[0], err
default:
return r, err
}
}
}
// IsConst returns if the Evaluable is a Parser.Const() value
func (e Evaluable) IsConst() bool {
pc := reflect.ValueOf(constant(nil)).Pointer()
pe := reflect.ValueOf(e).Pointer()
return pc == pe
}
func regEx(a, b Evaluable) (Evaluable, error) {
if !b.IsConst() {
return func(c context.Context, o interface{}) (interface{}, error) {
a, err := a.EvalString(c, o)
if err != nil {
return nil, err
}
b, err := b.EvalString(c, o)
if err != nil {
return nil, err
}
matched, err := regexp.MatchString(b, a)
return matched, err
}, nil
}
s, err := b.EvalString(context.TODO(), nil)
if err != nil {
return nil, err
}
regex, err := regexp.Compile(s)
if err != nil {
return nil, err
}
return func(c context.Context, v interface{}) (interface{}, error) {
s, err := a.EvalString(c, v)
if err != nil {
return nil, err
}
return regex.MatchString(s), nil
}, nil
}
func notRegEx(a, b Evaluable) (Evaluable, error) {
if !b.IsConst() {
return func(c context.Context, o interface{}) (interface{}, error) {
a, err := a.EvalString(c, o)
if err != nil {
return nil, err
}
b, err := b.EvalString(c, o)
if err != nil {
return nil, err
}
matched, err := regexp.MatchString(b, a)
return !matched, err
}, nil
}
s, err := b.EvalString(context.TODO(), nil)
if err != nil {
return nil, err
}
regex, err := regexp.Compile(s)
if err != nil {
return nil, err
}
return func(c context.Context, v interface{}) (interface{}, error) {
s, err := a.EvalString(c, v)
if err != nil {
return nil, err
}
return !regex.MatchString(s), nil
}, nil
}

128
server/vendor/github.com/PaesslerAG/gval/functions.go generated vendored Normal file
View File

@@ -0,0 +1,128 @@
package gval
import (
"context"
"fmt"
"reflect"
)
type function func(ctx context.Context, arguments ...interface{}) (interface{}, error)
func toFunc(f interface{}) function {
if f, ok := f.(func(arguments ...interface{}) (interface{}, error)); ok {
return function(func(ctx context.Context, arguments ...interface{}) (interface{}, error) {
var v interface{}
errCh := make(chan error, 1)
go func() {
defer func() {
if recovered := recover(); recovered != nil {
errCh <- fmt.Errorf("%v", recovered)
}
}()
result, err := f(arguments...)
v = result
errCh <- err
}()
select {
case <-ctx.Done():
return nil, ctx.Err()
case err := <-errCh:
close(errCh)
return v, err
}
})
}
if f, ok := f.(func(ctx context.Context, arguments ...interface{}) (interface{}, error)); ok {
return function(f)
}
fun := reflect.ValueOf(f)
t := fun.Type()
return func(ctx context.Context, args ...interface{}) (interface{}, error) {
var v interface{}
errCh := make(chan error, 1)
go func() {
defer func() {
if recovered := recover(); recovered != nil {
errCh <- fmt.Errorf("%v", recovered)
}
}()
in, err := createCallArguments(ctx, t, args)
if err != nil {
errCh <- err
return
}
out := fun.Call(in)
r := make([]interface{}, len(out))
for i, e := range out {
r[i] = e.Interface()
}
err = nil
errorInterface := reflect.TypeOf((*error)(nil)).Elem()
if len(r) > 0 && t.Out(len(r)-1).Implements(errorInterface) {
if r[len(r)-1] != nil {
err = r[len(r)-1].(error)
}
r = r[0 : len(r)-1]
}
switch len(r) {
case 0:
v = nil
case 1:
v = r[0]
default:
v = r
}
errCh <- err
}()
select {
case <-ctx.Done():
return nil, ctx.Err()
case err := <-errCh:
close(errCh)
return v, err
}
}
}
func createCallArguments(ctx context.Context, t reflect.Type, args []interface{}) ([]reflect.Value, error) {
variadic := t.IsVariadic()
numIn := t.NumIn()
// if first argument is a context, use the given execution context
if numIn > 0 {
thisFun := reflect.ValueOf(createCallArguments)
thisT := thisFun.Type()
if t.In(0) == thisT.In(0) {
args = append([]interface{}{ctx}, args...)
}
}
if (!variadic && len(args) != numIn) || (variadic && len(args) < numIn-1) {
return nil, fmt.Errorf("invalid number of parameters")
}
in := make([]reflect.Value, len(args))
var inType reflect.Type
for i, arg := range args {
if !variadic || i < numIn-1 {
inType = t.In(i)
} else if i == numIn-1 {
inType = t.In(numIn - 1).Elem()
}
argVal := reflect.ValueOf(arg)
if arg == nil {
argVal = reflect.Zero(reflect.TypeOf((*interface{})(nil)).Elem())
} else if !argVal.Type().AssignableTo(inType) {
return nil, fmt.Errorf("expected type %s for parameter %d but got %T",
inType.String(), i, arg)
}
in[i] = argVal
}
return in, nil
}

336
server/vendor/github.com/PaesslerAG/gval/gval.go generated vendored Normal file
View File

@@ -0,0 +1,336 @@
// Package gval provides a generic expression language.
// All functions, infix and prefix operators can be replaced by composing languages into a new one.
//
// The package contains concrete expression languages for common application in text, arithmetic, decimal arithmetic, propositional logic and so on.
// They can be used as basis for a custom expression language or to evaluate expressions directly.
package gval
import (
"context"
"fmt"
"math"
"reflect"
"text/scanner"
"time"
"github.com/shopspring/decimal"
)
// Evaluate given parameter with given expression in gval full language
func Evaluate(expression string, parameter interface{}, opts ...Language) (interface{}, error) {
return EvaluateWithContext(context.Background(), expression, parameter, opts...)
}
// Evaluate given parameter with given expression in gval full language using a context
func EvaluateWithContext(c context.Context, expression string, parameter interface{}, opts ...Language) (interface{}, error) {
l := full
if len(opts) > 0 {
l = NewLanguage(append([]Language{l}, opts...)...)
}
return l.EvaluateWithContext(c, expression, parameter)
}
// Full is the union of Arithmetic, Bitmask, Text, PropositionalLogic, TernaryOperator, and Json
//
// Operator in: a in b is true iff value a is an element of array b
// Operator ??: a ?? b returns a if a is not false or nil, otherwise n
//
// Function Date: Date(a) parses string a. a must match RFC3339, ISO8601, ruby date, or unix date
func Full(extensions ...Language) Language {
if len(extensions) == 0 {
return full
}
return NewLanguage(append([]Language{full}, extensions...)...)
}
// TernaryOperator contains following Operator
//
// ?: a ? b : c returns b if bool a is true, otherwise b
func TernaryOperator() Language {
return ternaryOperator
}
// Arithmetic contains base, plus(+), minus(-), divide(/), power(**), negative(-)
// and numerical order (<=,<,>,>=)
//
// Arithmetic operators expect float64 operands.
// Called with unfitting input, they try to convert the input to float64.
// They can parse strings and convert any type of int or float.
func Arithmetic() Language {
return arithmetic
}
// DecimalArithmetic contains base, plus(+), minus(-), divide(/), power(**), negative(-)
// and numerical order (<=,<,>,>=)
//
// DecimalArithmetic operators expect decimal.Decimal operands (github.com/shopspring/decimal)
// and are used to calculate money/decimal rather than floating point calculations.
// Called with unfitting input, they try to convert the input to decimal.Decimal.
// They can parse strings and convert any type of int or float.
func DecimalArithmetic() Language {
return decimalArithmetic
}
// Bitmask contains base, bitwise and(&), bitwise or(|) and bitwise not(^).
//
// Bitmask operators expect float64 operands.
// Called with unfitting input they try to convert the input to float64.
// They can parse strings and convert any type of int or float.
func Bitmask() Language {
return bitmask
}
// Text contains base, lexical order on strings (<=,<,>,>=),
// regex match (=~) and regex not match (!~)
func Text() Language {
return text
}
// PropositionalLogic contains base, not(!), and (&&), or (||) and Base.
//
// Propositional operator expect bool operands.
// Called with unfitting input they try to convert the input to bool.
// Numbers other than 0 and the strings "TRUE" and "true" are interpreted as true.
// 0 and the strings "FALSE" and "false" are interpreted as false.
func PropositionalLogic() Language {
return propositionalLogic
}
// JSON contains json objects ({string:expression,...})
// and json arrays ([expression, ...])
func JSON() Language {
return ljson
}
// Parentheses contains support for parentheses.
func Parentheses() Language {
return parentheses
}
// Ident contains support for variables and functions.
func Ident() Language {
return ident
}
// Base contains equal (==) and not equal (!=), perentheses and general support for variables, constants and functions
// It contains true, false, (floating point) number, string ("" or “) and char (”) constants
func Base() Language {
return base
}
var full = NewLanguage(arithmetic, bitmask, text, propositionalLogic, ljson,
InfixOperator("in", inArray),
InfixShortCircuit("??", func(a interface{}) (interface{}, bool) {
v := reflect.ValueOf(a)
return a, a != nil && !v.IsZero()
}),
InfixOperator("??", func(a, b interface{}) (interface{}, error) {
if v := reflect.ValueOf(a); a == nil || v.IsZero() {
return b, nil
}
return a, nil
}),
ternaryOperator,
Function("date", func(arguments ...interface{}) (interface{}, error) {
if len(arguments) != 1 {
return nil, fmt.Errorf("date() expects exactly one string argument")
}
s, ok := arguments[0].(string)
if !ok {
return nil, fmt.Errorf("date() expects exactly one string argument")
}
for _, format := range [...]string{
time.ANSIC,
time.UnixDate,
time.RubyDate,
time.Kitchen,
time.RFC3339,
time.RFC3339Nano,
"2006-01-02", // RFC 3339
"2006-01-02 15:04", // RFC 3339 with minutes
"2006-01-02 15:04:05", // RFC 3339 with seconds
"2006-01-02 15:04:05-07:00", // RFC 3339 with seconds and timezone
"2006-01-02T15Z0700", // ISO8601 with hour
"2006-01-02T15:04Z0700", // ISO8601 with minutes
"2006-01-02T15:04:05Z0700", // ISO8601 with seconds
"2006-01-02T15:04:05.999999999Z0700", // ISO8601 with nanoseconds
} {
ret, err := time.ParseInLocation(format, s, time.Local)
if err == nil {
return ret, nil
}
}
return nil, fmt.Errorf("date() could not parse %s", s)
}),
)
var ternaryOperator = PostfixOperator("?", parseIf)
var ljson = NewLanguage(
PrefixExtension('[', parseJSONArray),
PrefixExtension('{', parseJSONObject),
)
var arithmetic = NewLanguage(
InfixNumberOperator("+", func(a, b float64) (interface{}, error) { return a + b, nil }),
InfixNumberOperator("-", func(a, b float64) (interface{}, error) { return a - b, nil }),
InfixNumberOperator("*", func(a, b float64) (interface{}, error) { return a * b, nil }),
InfixNumberOperator("/", func(a, b float64) (interface{}, error) { return a / b, nil }),
InfixNumberOperator("%", func(a, b float64) (interface{}, error) { return math.Mod(a, b), nil }),
InfixNumberOperator("**", func(a, b float64) (interface{}, error) { return math.Pow(a, b), nil }),
InfixNumberOperator(">", func(a, b float64) (interface{}, error) { return a > b, nil }),
InfixNumberOperator(">=", func(a, b float64) (interface{}, error) { return a >= b, nil }),
InfixNumberOperator("<", func(a, b float64) (interface{}, error) { return a < b, nil }),
InfixNumberOperator("<=", func(a, b float64) (interface{}, error) { return a <= b, nil }),
InfixNumberOperator("==", func(a, b float64) (interface{}, error) { return a == b, nil }),
InfixNumberOperator("!=", func(a, b float64) (interface{}, error) { return a != b, nil }),
base,
)
var decimalArithmetic = NewLanguage(
InfixDecimalOperator("+", func(a, b decimal.Decimal) (interface{}, error) { return a.Add(b), nil }),
InfixDecimalOperator("-", func(a, b decimal.Decimal) (interface{}, error) { return a.Sub(b), nil }),
InfixDecimalOperator("*", func(a, b decimal.Decimal) (interface{}, error) { return a.Mul(b), nil }),
InfixDecimalOperator("/", func(a, b decimal.Decimal) (interface{}, error) { return a.Div(b), nil }),
InfixDecimalOperator("%", func(a, b decimal.Decimal) (interface{}, error) { return a.Mod(b), nil }),
InfixDecimalOperator("**", func(a, b decimal.Decimal) (interface{}, error) { return a.Pow(b), nil }),
InfixDecimalOperator(">", func(a, b decimal.Decimal) (interface{}, error) { return a.GreaterThan(b), nil }),
InfixDecimalOperator(">=", func(a, b decimal.Decimal) (interface{}, error) { return a.GreaterThanOrEqual(b), nil }),
InfixDecimalOperator("<", func(a, b decimal.Decimal) (interface{}, error) { return a.LessThan(b), nil }),
InfixDecimalOperator("<=", func(a, b decimal.Decimal) (interface{}, error) { return a.LessThanOrEqual(b), nil }),
InfixDecimalOperator("==", func(a, b decimal.Decimal) (interface{}, error) { return a.Equal(b), nil }),
InfixDecimalOperator("!=", func(a, b decimal.Decimal) (interface{}, error) { return !a.Equal(b), nil }),
base,
//Base is before these overrides so that the Base options are overridden
PrefixExtension(scanner.Int, parseDecimal),
PrefixExtension(scanner.Float, parseDecimal),
PrefixOperator("-", func(c context.Context, v interface{}) (interface{}, error) {
i, ok := convertToFloat(v)
if !ok {
return nil, fmt.Errorf("unexpected %v(%T) expected number", v, v)
}
return decimal.NewFromFloat(i).Neg(), nil
}),
)
var bitmask = NewLanguage(
InfixNumberOperator("^", func(a, b float64) (interface{}, error) { return float64(int64(a) ^ int64(b)), nil }),
InfixNumberOperator("&", func(a, b float64) (interface{}, error) { return float64(int64(a) & int64(b)), nil }),
InfixNumberOperator("|", func(a, b float64) (interface{}, error) { return float64(int64(a) | int64(b)), nil }),
InfixNumberOperator("<<", func(a, b float64) (interface{}, error) { return float64(int64(a) << uint64(b)), nil }),
InfixNumberOperator(">>", func(a, b float64) (interface{}, error) { return float64(int64(a) >> uint64(b)), nil }),
PrefixOperator("~", func(c context.Context, v interface{}) (interface{}, error) {
i, ok := convertToFloat(v)
if !ok {
return nil, fmt.Errorf("unexpected %T expected number", v)
}
return float64(^int64(i)), nil
}),
)
var text = NewLanguage(
InfixTextOperator("+", func(a, b string) (interface{}, error) { return fmt.Sprintf("%v%v", a, b), nil }),
InfixTextOperator("<", func(a, b string) (interface{}, error) { return a < b, nil }),
InfixTextOperator("<=", func(a, b string) (interface{}, error) { return a <= b, nil }),
InfixTextOperator(">", func(a, b string) (interface{}, error) { return a > b, nil }),
InfixTextOperator(">=", func(a, b string) (interface{}, error) { return a >= b, nil }),
InfixEvalOperator("=~", regEx),
InfixEvalOperator("!~", notRegEx),
base,
)
var propositionalLogic = NewLanguage(
PrefixOperator("!", func(c context.Context, v interface{}) (interface{}, error) {
b, ok := convertToBool(v)
if !ok {
return nil, fmt.Errorf("unexpected %T expected bool", v)
}
return !b, nil
}),
InfixShortCircuit("&&", func(a interface{}) (interface{}, bool) { return false, a == false }),
InfixBoolOperator("&&", func(a, b bool) (interface{}, error) { return a && b, nil }),
InfixShortCircuit("||", func(a interface{}) (interface{}, bool) { return true, a == true }),
InfixBoolOperator("||", func(a, b bool) (interface{}, error) { return a || b, nil }),
InfixBoolOperator("==", func(a, b bool) (interface{}, error) { return a == b, nil }),
InfixBoolOperator("!=", func(a, b bool) (interface{}, error) { return a != b, nil }),
base,
)
var parentheses = NewLanguage(
PrefixExtension('(', parseParentheses),
)
var ident = NewLanguage(
PrefixMetaPrefix(scanner.Ident, parseIdent),
)
var base = NewLanguage(
PrefixExtension(scanner.Int, parseNumber),
PrefixExtension(scanner.Float, parseNumber),
PrefixOperator("-", func(c context.Context, v interface{}) (interface{}, error) {
i, ok := convertToFloat(v)
if !ok {
return nil, fmt.Errorf("unexpected %v(%T) expected number", v, v)
}
return -i, nil
}),
PrefixExtension(scanner.String, parseString),
PrefixExtension(scanner.Char, parseString),
PrefixExtension(scanner.RawString, parseString),
Constant("true", true),
Constant("false", false),
InfixOperator("==", func(a, b interface{}) (interface{}, error) { return reflect.DeepEqual(a, b), nil }),
InfixOperator("!=", func(a, b interface{}) (interface{}, error) { return !reflect.DeepEqual(a, b), nil }),
parentheses,
Precedence("??", 0),
Precedence("||", 20),
Precedence("&&", 21),
Precedence("==", 40),
Precedence("!=", 40),
Precedence(">", 40),
Precedence(">=", 40),
Precedence("<", 40),
Precedence("<=", 40),
Precedence("=~", 40),
Precedence("!~", 40),
Precedence("in", 40),
Precedence("^", 60),
Precedence("&", 60),
Precedence("|", 60),
Precedence("<<", 90),
Precedence(">>", 90),
Precedence("+", 120),
Precedence("-", 120),
Precedence("*", 150),
Precedence("/", 150),
Precedence("%", 150),
Precedence("**", 200),
ident,
)

281
server/vendor/github.com/PaesslerAG/gval/language.go generated vendored Normal file
View File

@@ -0,0 +1,281 @@
package gval
import (
"context"
"fmt"
"text/scanner"
"unicode"
"github.com/shopspring/decimal"
)
// Language is an expression language
type Language struct {
prefixes map[interface{}]extension
operators map[string]operator
operatorSymbols map[rune]struct{}
init extension
def extension
selector func(Evaluables) Evaluable
}
// NewLanguage returns the union of given Languages as new Language.
func NewLanguage(bases ...Language) Language {
l := newLanguage()
for _, base := range bases {
for i, e := range base.prefixes {
l.prefixes[i] = e
}
for i, e := range base.operators {
l.operators[i] = e.merge(l.operators[i])
l.operators[i].initiate(i)
}
for i := range base.operatorSymbols {
l.operatorSymbols[i] = struct{}{}
}
if base.init != nil {
l.init = base.init
}
if base.def != nil {
l.def = base.def
}
if base.selector != nil {
l.selector = base.selector
}
}
return l
}
func newLanguage() Language {
return Language{
prefixes: map[interface{}]extension{},
operators: map[string]operator{},
operatorSymbols: map[rune]struct{}{},
}
}
// NewEvaluable returns an Evaluable for given expression in the specified language
func (l Language) NewEvaluable(expression string) (Evaluable, error) {
return l.NewEvaluableWithContext(context.Background(), expression)
}
// NewEvaluableWithContext returns an Evaluable for given expression in the specified language using context
func (l Language) NewEvaluableWithContext(c context.Context, expression string) (Evaluable, error) {
p := newParser(expression, l)
eval, err := p.parse(c)
if err == nil && p.isCamouflaged() && p.lastScan != scanner.EOF {
err = p.camouflage
}
if err != nil {
pos := p.scanner.Pos()
return nil, fmt.Errorf("parsing error: %s - %d:%d %w", p.scanner.Position, pos.Line, pos.Column, err)
}
return eval, nil
}
// Evaluate given parameter with given expression
func (l Language) Evaluate(expression string, parameter interface{}) (interface{}, error) {
return l.EvaluateWithContext(context.Background(), expression, parameter)
}
// Evaluate given parameter with given expression using context
func (l Language) EvaluateWithContext(c context.Context, expression string, parameter interface{}) (interface{}, error) {
eval, err := l.NewEvaluableWithContext(c, expression)
if err != nil {
return nil, err
}
v, err := eval(c, parameter)
if err != nil {
return nil, fmt.Errorf("can not evaluate %s: %w", expression, err)
}
return v, nil
}
// Function returns a Language with given function.
// Function has no conversion for input types.
//
// If the function returns an error it must be the last return parameter.
//
// If the function has (without the error) more then one return parameter,
// it returns them as []interface{}.
func Function(name string, function interface{}) Language {
l := newLanguage()
l.prefixes[name] = func(c context.Context, p *Parser) (eval Evaluable, err error) {
args := []Evaluable{}
scan := p.Scan()
switch scan {
case '(':
args, err = p.parseArguments(c)
if err != nil {
return nil, err
}
default:
p.Camouflage("function call", '(')
}
return p.callFunc(toFunc(function), args...), nil
}
return l
}
// Constant returns a Language with given constant
func Constant(name string, value interface{}) Language {
l := newLanguage()
l.prefixes[l.makePrefixKey(name)] = func(c context.Context, p *Parser) (eval Evaluable, err error) {
return p.Const(value), nil
}
return l
}
// PrefixExtension extends a Language
func PrefixExtension(r rune, ext func(context.Context, *Parser) (Evaluable, error)) Language {
l := newLanguage()
l.prefixes[r] = ext
return l
}
// Init is a language that does no parsing, but invokes the given function when
// parsing starts. It is incumbent upon the function to call ParseExpression to
// continue parsing.
//
// This function can be used to customize the parser settings, such as
// whitespace or ident behavior.
func Init(ext func(context.Context, *Parser) (Evaluable, error)) Language {
l := newLanguage()
l.init = ext
return l
}
// DefaultExtension is a language that runs the given function if no other
// prefix matches.
func DefaultExtension(ext func(context.Context, *Parser) (Evaluable, error)) Language {
l := newLanguage()
l.def = ext
return l
}
// PrefixMetaPrefix chooses a Prefix to be executed
func PrefixMetaPrefix(r rune, ext func(context.Context, *Parser) (call string, alternative func() (Evaluable, error), err error)) Language {
l := newLanguage()
l.prefixes[r] = func(c context.Context, p *Parser) (Evaluable, error) {
call, alternative, err := ext(c, p)
if err != nil {
return nil, err
}
if prefix, ok := p.prefixes[l.makePrefixKey(call)]; ok {
return prefix(c, p)
}
return alternative()
}
return l
}
// PrefixOperator returns a Language with given prefix
func PrefixOperator(name string, e Evaluable) Language {
l := newLanguage()
l.prefixes[l.makePrefixKey(name)] = func(c context.Context, p *Parser) (Evaluable, error) {
eval, err := p.ParseNextExpression(c)
if err != nil {
return nil, err
}
prefix := func(c context.Context, v interface{}) (interface{}, error) {
a, err := eval(c, v)
if err != nil {
return nil, err
}
return e(c, a)
}
if eval.IsConst() {
v, err := prefix(c, nil)
if err != nil {
return nil, err
}
prefix = p.Const(v)
}
return prefix, nil
}
return l
}
// PostfixOperator extends a Language.
func PostfixOperator(name string, ext func(context.Context, *Parser, Evaluable) (Evaluable, error)) Language {
l := newLanguage()
l.operators[l.makeInfixKey(name)] = postfix{
f: func(c context.Context, p *Parser, eval Evaluable, pre operatorPrecedence) (Evaluable, error) {
return ext(c, p, eval)
},
}
return l
}
// InfixOperator for two arbitrary values.
func InfixOperator(name string, f func(a, b interface{}) (interface{}, error)) Language {
return newLanguageOperator(name, &infix{arbitrary: f})
}
// InfixShortCircuit operator is called after the left operand is evaluated.
func InfixShortCircuit(name string, f func(a interface{}) (interface{}, bool)) Language {
return newLanguageOperator(name, &infix{shortCircuit: f})
}
// InfixTextOperator for two text values.
func InfixTextOperator(name string, f func(a, b string) (interface{}, error)) Language {
return newLanguageOperator(name, &infix{text: f})
}
// InfixNumberOperator for two number values.
func InfixNumberOperator(name string, f func(a, b float64) (interface{}, error)) Language {
return newLanguageOperator(name, &infix{number: f})
}
// InfixDecimalOperator for two decimal values.
func InfixDecimalOperator(name string, f func(a, b decimal.Decimal) (interface{}, error)) Language {
return newLanguageOperator(name, &infix{decimal: f})
}
// InfixBoolOperator for two bool values.
func InfixBoolOperator(name string, f func(a, b bool) (interface{}, error)) Language {
return newLanguageOperator(name, &infix{boolean: f})
}
// Precedence of operator. The Operator with higher operatorPrecedence is evaluated first.
func Precedence(name string, operatorPrecendence uint8) Language {
return newLanguageOperator(name, operatorPrecedence(operatorPrecendence))
}
// InfixEvalOperator operates on the raw operands.
// Therefore it cannot be combined with operators for other operand types.
func InfixEvalOperator(name string, f func(a, b Evaluable) (Evaluable, error)) Language {
return newLanguageOperator(name, directInfix{infixBuilder: f})
}
func newLanguageOperator(name string, op operator) Language {
op.initiate(name)
l := newLanguage()
l.operators[l.makeInfixKey(name)] = op
return l
}
func (l *Language) makePrefixKey(key string) interface{} {
runes := []rune(key)
if len(runes) == 1 && !unicode.IsLetter(runes[0]) {
return runes[0]
}
return key
}
func (l *Language) makeInfixKey(key string) string {
for _, r := range key {
l.operatorSymbols[r] = struct{}{}
}
return key
}
// VariableSelector returns a Language which uses given variable selector.
// It must be combined with a Language that uses the vatiable selector. E.g. gval.Base().
func VariableSelector(selector func(path Evaluables) Evaluable) Language {
l := newLanguage()
l.selector = selector
return l
}

405
server/vendor/github.com/PaesslerAG/gval/operator.go generated vendored Normal file
View File

@@ -0,0 +1,405 @@
package gval
import (
"context"
"fmt"
"reflect"
"strconv"
"strings"
"github.com/shopspring/decimal"
)
type stage struct {
Evaluable
infixBuilder
operatorPrecedence
}
type stageStack []stage //operatorPrecedence in stacktStage is continuously, monotone ascending
func (s *stageStack) push(b stage) error {
for len(*s) > 0 && s.peek().operatorPrecedence >= b.operatorPrecedence {
a := s.pop()
eval, err := a.infixBuilder(a.Evaluable, b.Evaluable)
if err != nil {
return err
}
if a.IsConst() && b.IsConst() {
v, err := eval(nil, nil)
if err != nil {
return err
}
b.Evaluable = constant(v)
continue
}
b.Evaluable = eval
}
*s = append(*s, b)
return nil
}
func (s *stageStack) peek() stage {
return (*s)[len(*s)-1]
}
func (s *stageStack) pop() stage {
a := s.peek()
(*s) = (*s)[:len(*s)-1]
return a
}
type infixBuilder func(a, b Evaluable) (Evaluable, error)
func (l Language) isSymbolOperation(r rune) bool {
_, in := l.operatorSymbols[r]
return in
}
func (l Language) isOperatorPrefix(op string) bool {
for k := range l.operators {
if strings.HasPrefix(k, op) {
return true
}
}
return false
}
func (op *infix) initiate(name string) {
f := func(a, b interface{}) (interface{}, error) {
return nil, fmt.Errorf("invalid operation (%T) %s (%T)", a, name, b)
}
if op.arbitrary != nil {
f = op.arbitrary
}
for _, typeConvertion := range []bool{true, false} {
if op.text != nil && (!typeConvertion || op.arbitrary == nil) {
f = getStringOpFunc(op.text, f, typeConvertion)
}
if op.boolean != nil {
f = getBoolOpFunc(op.boolean, f, typeConvertion)
}
if op.number != nil {
f = getFloatOpFunc(op.number, f, typeConvertion)
}
if op.decimal != nil {
f = getDecimalOpFunc(op.decimal, f, typeConvertion)
}
}
if op.shortCircuit == nil {
op.builder = func(a, b Evaluable) (Evaluable, error) {
return func(c context.Context, x interface{}) (interface{}, error) {
a, err := a(c, x)
if err != nil {
return nil, err
}
b, err := b(c, x)
if err != nil {
return nil, err
}
return f(a, b)
}, nil
}
return
}
shortF := op.shortCircuit
op.builder = func(a, b Evaluable) (Evaluable, error) {
return func(c context.Context, x interface{}) (interface{}, error) {
a, err := a(c, x)
if err != nil {
return nil, err
}
if r, ok := shortF(a); ok {
return r, nil
}
b, err := b(c, x)
if err != nil {
return nil, err
}
return f(a, b)
}, nil
}
}
type opFunc func(a, b interface{}) (interface{}, error)
func getStringOpFunc(s func(a, b string) (interface{}, error), f opFunc, typeConversion bool) opFunc {
if typeConversion {
return func(a, b interface{}) (interface{}, error) {
if a != nil && b != nil {
return s(fmt.Sprintf("%v", a), fmt.Sprintf("%v", b))
}
return f(a, b)
}
}
return func(a, b interface{}) (interface{}, error) {
s1, k := a.(string)
s2, l := b.(string)
if k && l {
return s(s1, s2)
}
return f(a, b)
}
}
func convertToBool(o interface{}) (bool, bool) {
if b, ok := o.(bool); ok {
return b, true
}
v := reflect.ValueOf(o)
if v.Kind() == reflect.Func {
if vt := v.Type(); vt.NumIn() == 0 && vt.NumOut() == 1 {
retType := vt.Out(0)
if retType.Kind() == reflect.Bool {
funcResults := v.Call([]reflect.Value{})
v = funcResults[0]
o = v.Interface()
}
}
}
for o != nil && v.Kind() == reflect.Ptr {
v = v.Elem()
if !v.IsValid() {
return false, false
}
o = v.Interface()
}
if o == false || o == nil || o == "false" || o == "FALSE" {
return false, true
}
if o == true || o == "true" || o == "TRUE" {
return true, true
}
if f, ok := convertToFloat(o); ok {
return f != 0., true
}
return false, false
}
func getBoolOpFunc(o func(a, b bool) (interface{}, error), f opFunc, typeConversion bool) opFunc {
if typeConversion {
return func(a, b interface{}) (interface{}, error) {
x, k := convertToBool(a)
y, l := convertToBool(b)
if k && l {
return o(x, y)
}
return f(a, b)
}
}
return func(a, b interface{}) (interface{}, error) {
x, k := a.(bool)
y, l := b.(bool)
if k && l {
return o(x, y)
}
return f(a, b)
}
}
func convertToFloat(o interface{}) (float64, bool) {
if i, ok := o.(float64); ok {
return i, true
}
v := reflect.ValueOf(o)
for o != nil && v.Kind() == reflect.Ptr {
v = v.Elem()
if !v.IsValid() {
return 0, false
}
o = v.Interface()
}
switch v.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return float64(v.Int()), true
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return float64(v.Uint()), true
case reflect.Float32, reflect.Float64:
return v.Float(), true
}
if s, ok := o.(string); ok {
f, err := strconv.ParseFloat(s, 64)
if err == nil {
return f, true
}
}
return 0, false
}
func getFloatOpFunc(o func(a, b float64) (interface{}, error), f opFunc, typeConversion bool) opFunc {
if typeConversion {
return func(a, b interface{}) (interface{}, error) {
x, k := convertToFloat(a)
y, l := convertToFloat(b)
if k && l {
return o(x, y)
}
return f(a, b)
}
}
return func(a, b interface{}) (interface{}, error) {
x, k := a.(float64)
y, l := b.(float64)
if k && l {
return o(x, y)
}
return f(a, b)
}
}
func convertToDecimal(o interface{}) (decimal.Decimal, bool) {
if i, ok := o.(decimal.Decimal); ok {
return i, true
}
if i, ok := o.(float64); ok {
return decimal.NewFromFloat(i), true
}
v := reflect.ValueOf(o)
for o != nil && v.Kind() == reflect.Ptr {
v = v.Elem()
if !v.IsValid() {
return decimal.Zero, false
}
o = v.Interface()
}
switch v.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return decimal.NewFromInt(v.Int()), true
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return decimal.NewFromFloat(float64(v.Uint())), true
case reflect.Float32, reflect.Float64:
return decimal.NewFromFloat(v.Float()), true
}
if s, ok := o.(string); ok {
f, err := strconv.ParseFloat(s, 64)
if err == nil {
return decimal.NewFromFloat(f), true
}
}
return decimal.Zero, false
}
func getDecimalOpFunc(o func(a, b decimal.Decimal) (interface{}, error), f opFunc, typeConversion bool) opFunc {
if typeConversion {
return func(a, b interface{}) (interface{}, error) {
x, k := convertToDecimal(a)
y, l := convertToDecimal(b)
if k && l {
return o(x, y)
}
return f(a, b)
}
}
return func(a, b interface{}) (interface{}, error) {
x, k := a.(decimal.Decimal)
y, l := b.(decimal.Decimal)
if k && l {
return o(x, y)
}
return f(a, b)
}
}
type operator interface {
merge(operator) operator
precedence() operatorPrecedence
initiate(name string)
}
type operatorPrecedence uint8
func (pre operatorPrecedence) merge(op operator) operator {
if op, ok := op.(operatorPrecedence); ok {
if op > pre {
return op
}
return pre
}
if op == nil {
return pre
}
return op.merge(pre)
}
func (pre operatorPrecedence) precedence() operatorPrecedence {
return pre
}
func (pre operatorPrecedence) initiate(name string) {}
type infix struct {
operatorPrecedence
number func(a, b float64) (interface{}, error)
decimal func(a, b decimal.Decimal) (interface{}, error)
boolean func(a, b bool) (interface{}, error)
text func(a, b string) (interface{}, error)
arbitrary func(a, b interface{}) (interface{}, error)
shortCircuit func(a interface{}) (interface{}, bool)
builder infixBuilder
}
func (op infix) merge(op2 operator) operator {
switch op2 := op2.(type) {
case *infix:
if op.number == nil {
op.number = op2.number
}
if op.decimal == nil {
op.decimal = op2.decimal
}
if op.boolean == nil {
op.boolean = op2.boolean
}
if op.text == nil {
op.text = op2.text
}
if op.arbitrary == nil {
op.arbitrary = op2.arbitrary
}
if op.shortCircuit == nil {
op.shortCircuit = op2.shortCircuit
}
}
if op2 != nil && op2.precedence() > op.operatorPrecedence {
op.operatorPrecedence = op2.precedence()
}
return &op
}
type directInfix struct {
operatorPrecedence
infixBuilder
}
func (op directInfix) merge(op2 operator) operator {
switch op2 := op2.(type) {
case operatorPrecedence:
op.operatorPrecedence = op2
}
if op2 != nil && op2.precedence() > op.operatorPrecedence {
op.operatorPrecedence = op2.precedence()
}
return op
}
type extension func(context.Context, *Parser) (Evaluable, error)
type postfix struct {
operatorPrecedence
f func(context.Context, *Parser, Evaluable, operatorPrecedence) (Evaluable, error)
}
func (op postfix) merge(op2 operator) operator {
switch op2 := op2.(type) {
case postfix:
if op2.f != nil {
op.f = op2.f
}
}
if op2 != nil && op2.precedence() > op.operatorPrecedence {
op.operatorPrecedence = op2.precedence()
}
return op
}

347
server/vendor/github.com/PaesslerAG/gval/parse.go generated vendored Normal file
View File

@@ -0,0 +1,347 @@
package gval
import (
"context"
"fmt"
"reflect"
"strconv"
"text/scanner"
"github.com/shopspring/decimal"
)
// ParseExpression scans an expression into an Evaluable.
func (p *Parser) ParseExpression(c context.Context) (eval Evaluable, err error) {
stack := stageStack{}
for {
eval, err = p.ParseNextExpression(c)
if err != nil {
return nil, err
}
if stage, err := p.parseOperator(c, &stack, eval); err != nil {
return nil, err
} else if err = stack.push(stage); err != nil {
return nil, err
}
if stack.peek().infixBuilder == nil {
return stack.pop().Evaluable, nil
}
}
}
// ParseNextExpression scans the expression ignoring following operators
func (p *Parser) ParseNextExpression(c context.Context) (eval Evaluable, err error) {
scan := p.Scan()
ex, ok := p.prefixes[scan]
if !ok {
if scan != scanner.EOF && p.def != nil {
return p.def(c, p)
}
return nil, p.Expected("extensions")
}
return ex(c, p)
}
// ParseSublanguage sets the next language for this parser to parse and calls
// its initialization function, usually ParseExpression.
func (p *Parser) ParseSublanguage(c context.Context, l Language) (Evaluable, error) {
if p.isCamouflaged() {
panic("can not ParseSublanguage() on camouflaged Parser")
}
curLang := p.Language
curWhitespace := p.scanner.Whitespace
curMode := p.scanner.Mode
curIsIdentRune := p.scanner.IsIdentRune
p.Language = l
p.resetScannerProperties()
defer func() {
p.Language = curLang
p.scanner.Whitespace = curWhitespace
p.scanner.Mode = curMode
p.scanner.IsIdentRune = curIsIdentRune
}()
return p.parse(c)
}
func (p *Parser) parse(c context.Context) (Evaluable, error) {
if p.init != nil {
return p.init(c, p)
}
return p.ParseExpression(c)
}
func parseString(c context.Context, p *Parser) (Evaluable, error) {
s, err := strconv.Unquote(p.TokenText())
if err != nil {
return nil, fmt.Errorf("could not parse string: %w", err)
}
return p.Const(s), nil
}
func parseNumber(c context.Context, p *Parser) (Evaluable, error) {
n, err := strconv.ParseFloat(p.TokenText(), 64)
if err != nil {
return nil, err
}
return p.Const(n), nil
}
func parseDecimal(c context.Context, p *Parser) (Evaluable, error) {
n, err := strconv.ParseFloat(p.TokenText(), 64)
if err != nil {
return nil, err
}
return p.Const(decimal.NewFromFloat(n)), nil
}
func parseParentheses(c context.Context, p *Parser) (Evaluable, error) {
eval, err := p.ParseExpression(c)
if err != nil {
return nil, err
}
switch p.Scan() {
case ')':
return eval, nil
default:
return nil, p.Expected("parentheses", ')')
}
}
func (p *Parser) parseOperator(c context.Context, stack *stageStack, eval Evaluable) (st stage, err error) {
for {
scan := p.Scan()
op := p.TokenText()
mustOp := false
if p.isSymbolOperation(scan) {
scan = p.Peek()
for p.isSymbolOperation(scan) && p.isOperatorPrefix(op+string(scan)) {
mustOp = true
op += string(scan)
p.Next()
scan = p.Peek()
}
} else if scan != scanner.Ident {
p.Camouflage("operator")
return stage{Evaluable: eval}, nil
}
switch operator := p.operators[op].(type) {
case *infix:
return stage{
Evaluable: eval,
infixBuilder: operator.builder,
operatorPrecedence: operator.operatorPrecedence,
}, nil
case directInfix:
return stage{
Evaluable: eval,
infixBuilder: operator.infixBuilder,
operatorPrecedence: operator.operatorPrecedence,
}, nil
case postfix:
if err = stack.push(stage{
operatorPrecedence: operator.operatorPrecedence,
Evaluable: eval,
}); err != nil {
return stage{}, err
}
eval, err = operator.f(c, p, stack.pop().Evaluable, operator.operatorPrecedence)
if err != nil {
return
}
continue
}
if !mustOp {
p.Camouflage("operator")
return stage{Evaluable: eval}, nil
}
return stage{}, fmt.Errorf("unknown operator %s", op)
}
}
func parseIdent(c context.Context, p *Parser) (call string, alternative func() (Evaluable, error), err error) {
token := p.TokenText()
return token,
func() (Evaluable, error) {
fullname := token
keys := []Evaluable{p.Const(token)}
for {
scan := p.Scan()
switch scan {
case '.':
scan = p.Scan()
switch scan {
case scanner.Ident:
token = p.TokenText()
keys = append(keys, p.Const(token))
default:
return nil, p.Expected("field", scanner.Ident)
}
case '(':
args, err := p.parseArguments(c)
if err != nil {
return nil, err
}
return p.callEvaluable(fullname, p.Var(keys...), args...), nil
case '[':
key, err := p.ParseExpression(c)
if err != nil {
return nil, err
}
switch p.Scan() {
case ']':
keys = append(keys, key)
default:
return nil, p.Expected("array key", ']')
}
default:
p.Camouflage("variable", '.', '(', '[')
return p.Var(keys...), nil
}
}
}, nil
}
func (p *Parser) parseArguments(c context.Context) (args []Evaluable, err error) {
if p.Scan() == ')' {
return
}
p.Camouflage("scan arguments", ')')
for {
arg, err := p.ParseExpression(c)
args = append(args, arg)
if err != nil {
return nil, err
}
switch p.Scan() {
case ')':
return args, nil
case ',':
default:
return nil, p.Expected("arguments", ')', ',')
}
}
}
func inArray(a, b interface{}) (interface{}, error) {
col, ok := b.([]interface{})
if !ok {
return nil, fmt.Errorf("expected type []interface{} for in operator but got %T", b)
}
for _, value := range col {
if reflect.DeepEqual(a, value) {
return true, nil
}
}
return false, nil
}
func parseIf(c context.Context, p *Parser, e Evaluable) (Evaluable, error) {
a, err := p.ParseExpression(c)
if err != nil {
return nil, err
}
b := p.Const(nil)
switch p.Scan() {
case ':':
b, err = p.ParseExpression(c)
if err != nil {
return nil, err
}
case scanner.EOF:
default:
return nil, p.Expected("<> ? <> : <>", ':', scanner.EOF)
}
return func(c context.Context, v interface{}) (interface{}, error) {
x, err := e(c, v)
if err != nil {
return nil, err
}
if valX := reflect.ValueOf(x); x == nil || valX.IsZero() {
return b(c, v)
}
return a(c, v)
}, nil
}
func parseJSONArray(c context.Context, p *Parser) (Evaluable, error) {
evals := []Evaluable{}
for {
switch p.Scan() {
default:
p.Camouflage("array", ',', ']')
eval, err := p.ParseExpression(c)
if err != nil {
return nil, err
}
evals = append(evals, eval)
case ',':
case ']':
return func(c context.Context, v interface{}) (interface{}, error) {
vs := make([]interface{}, len(evals))
for i, e := range evals {
eval, err := e(c, v)
if err != nil {
return nil, err
}
vs[i] = eval
}
return vs, nil
}, nil
}
}
}
func parseJSONObject(c context.Context, p *Parser) (Evaluable, error) {
type kv struct {
key Evaluable
value Evaluable
}
evals := []kv{}
for {
switch p.Scan() {
default:
p.Camouflage("object", ',', '}')
key, err := p.ParseExpression(c)
if err != nil {
return nil, err
}
if p.Scan() != ':' {
if err != nil {
return nil, p.Expected("object", ':')
}
}
value, err := p.ParseExpression(c)
if err != nil {
return nil, err
}
evals = append(evals, kv{key, value})
case ',':
case '}':
return func(c context.Context, v interface{}) (interface{}, error) {
vs := map[string]interface{}{}
for _, e := range evals {
value, err := e.value(c, v)
if err != nil {
return nil, err
}
key, err := e.key.EvalString(c, v)
if err != nil {
return nil, err
}
vs[key] = value
}
return vs, nil
}, nil
}
}
}

147
server/vendor/github.com/PaesslerAG/gval/parser.go generated vendored Normal file
View File

@@ -0,0 +1,147 @@
package gval
import (
"bytes"
"fmt"
"strings"
"text/scanner"
"unicode"
)
// Parser parses expressions in a Language into an Evaluable
type Parser struct {
scanner scanner.Scanner
Language
lastScan rune
camouflage error
}
func newParser(expression string, l Language) *Parser {
sc := scanner.Scanner{}
sc.Init(strings.NewReader(expression))
sc.Error = func(*scanner.Scanner, string) {}
sc.Filename = expression + "\t"
p := &Parser{scanner: sc, Language: l}
p.resetScannerProperties()
return p
}
func (p *Parser) resetScannerProperties() {
p.scanner.Whitespace = scanner.GoWhitespace
p.scanner.Mode = scanner.GoTokens
p.scanner.IsIdentRune = func(r rune, pos int) bool {
return unicode.IsLetter(r) || r == '_' || (pos > 0 && unicode.IsDigit(r))
}
}
// SetWhitespace sets the behavior of the whitespace matcher. The given
// characters must be less than or equal to 0x20 (' ').
func (p *Parser) SetWhitespace(chars ...rune) {
var mask uint64
for _, char := range chars {
mask |= 1 << uint(char)
}
p.scanner.Whitespace = mask
}
// SetMode sets the tokens that the underlying scanner will match.
func (p *Parser) SetMode(mode uint) {
p.scanner.Mode = mode
}
// SetIsIdentRuneFunc sets the function that matches ident characters in the
// underlying scanner.
func (p *Parser) SetIsIdentRuneFunc(fn func(ch rune, i int) bool) {
p.scanner.IsIdentRune = fn
}
// Scan reads the next token or Unicode character from source and returns it.
// It only recognizes tokens t for which the respective Mode bit (1<<-t) is set.
// It returns scanner.EOF at the end of the source.
func (p *Parser) Scan() rune {
if p.isCamouflaged() {
p.camouflage = nil
return p.lastScan
}
p.camouflage = nil
p.lastScan = p.scanner.Scan()
return p.lastScan
}
func (p *Parser) isCamouflaged() bool {
return p.camouflage != nil && p.camouflage != errCamouflageAfterNext
}
// Camouflage rewind the last Scan(). The Parser holds the camouflage error until
// the next Scan()
// Do not call Rewind() on a camouflaged Parser
func (p *Parser) Camouflage(unit string, expected ...rune) {
if p.isCamouflaged() {
panic(fmt.Errorf("can only Camouflage() after Scan(): %w", p.camouflage))
}
p.camouflage = p.Expected(unit, expected...)
}
// Peek returns the next Unicode character in the source without advancing
// the scanner. It returns EOF if the scanner's position is at the last
// character of the source.
// Do not call Peek() on a camouflaged Parser
func (p *Parser) Peek() rune {
if p.isCamouflaged() {
panic("can not Peek() on camouflaged Parser")
}
return p.scanner.Peek()
}
var errCamouflageAfterNext = fmt.Errorf("Camouflage() after Next()")
// Next reads and returns the next Unicode character.
// It returns EOF at the end of the source.
// Do not call Next() on a camouflaged Parser
func (p *Parser) Next() rune {
if p.isCamouflaged() {
panic("can not Next() on camouflaged Parser")
}
p.camouflage = errCamouflageAfterNext
return p.scanner.Next()
}
// TokenText returns the string corresponding to the most recently scanned token.
// Valid after calling Scan().
func (p *Parser) TokenText() string {
return p.scanner.TokenText()
}
// Expected returns an error signaling an unexpected Scan() result
func (p *Parser) Expected(unit string, expected ...rune) error {
return unexpectedRune{unit, expected, p.lastScan}
}
type unexpectedRune struct {
unit string
expected []rune
got rune
}
func (err unexpectedRune) Error() string {
exp := bytes.Buffer{}
runes := err.expected
switch len(runes) {
default:
for _, r := range runes[:len(runes)-2] {
exp.WriteString(scanner.TokenString(r))
exp.WriteString(", ")
}
fallthrough
case 2:
exp.WriteString(scanner.TokenString(runes[len(runes)-2]))
exp.WriteString(" or ")
fallthrough
case 1:
exp.WriteString(scanner.TokenString(runes[len(runes)-1]))
case 0:
return fmt.Sprintf("unexpected %s while scanning %s", scanner.TokenString(err.got), err.unit)
}
return fmt.Sprintf("unexpected %s while scanning %s expected %s", scanner.TokenString(err.got), err.unit, exp.String())
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@@ -0,0 +1,30 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
coverage.out
manual_test.go
*.out
*.err
.vscode

View File

@@ -0,0 +1,6 @@
language: go
script: ./test.sh
go:
- 1.9

12
server/vendor/github.com/PaesslerAG/jsonpath/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,12 @@
Copyright (c) 2017, Paessler AG <support@paessler.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

11
server/vendor/github.com/PaesslerAG/jsonpath/README.md generated vendored Normal file
View File

@@ -0,0 +1,11 @@
JSONPath
====
[![Build Status](https://api.travis-ci.org/PaesslerAG/jsonpath.svg?branch=master)](https://travis-ci.org/PaesslerAG/jsonpath)
[![Godoc](https://godoc.org/github.com/PaesslerAG/jsonpath?status.png)](https://godoc.org/github.com/PaesslerAG/jsonpath)
JSONPath is a complete implementation of [http://goessner.net/articles/JsonPath/](http://goessner.net/articles/JsonPath/).
JSONPath can be combined with a script language. In many web samples it's combined with javascript. This framework comes without a script language but can be easily extended with one. See [example](https://godoc.org/github.com/PaesslerAG/jsonpath#example-package--Gval).
It is based on [Gval](https://github.com/PaesslerAG/gval) and can be combined with the modular expression languages based on gval.
So for script features like multiply, length, regex or many more take a look at the documentation in the [GoDoc](https://godoc.org/github.com/PaesslerAG/jsonpath).

View File

@@ -0,0 +1,54 @@
// Package jsonpath is an implementation of http://goessner.net/articles/JsonPath/
// If a JSONPath contains one of
// [key1, key2 ...], .., *, [min:max], [min:max:step], (? expression)
// all matchs are listed in an []interface{}
//
// The package comes with an extension of JSONPath to access the wildcard values of a match.
// If the JSONPath is used inside of a JSON object, you can use placeholder '#' or '#i' with natural number i
// to access all wildcards values or the ith wildcard
//
// This package can be extended with gval modules for script features like multiply, length, regex or many more.
// So take a look at github.com/PaesslerAG/gval.
package jsonpath
import (
"context"
"github.com/PaesslerAG/gval"
)
// New returns an selector for given JSONPath
func New(path string) (gval.Evaluable, error) {
return lang.NewEvaluable(path)
}
//Get executes given JSONPath on given value
func Get(path string, value interface{}) (interface{}, error) {
eval, err := lang.NewEvaluable(path)
if err != nil {
return nil, err
}
return eval(context.Background(), value)
}
var lang = gval.NewLanguage(
gval.Base(),
gval.PrefixExtension('$', parseRootPath),
gval.PrefixExtension('@', parseCurrentPath),
)
//Language is the JSONPath Language
func Language() gval.Language {
return lang
}
var placeholderExtension = gval.NewLanguage(
lang,
gval.PrefixExtension('{', parseJSONObject),
gval.PrefixExtension('#', parsePlaceholder),
)
//PlaceholderExtension is the JSONPath Language with placeholder
func PlaceholderExtension() gval.Language {
return placeholderExtension
}

204
server/vendor/github.com/PaesslerAG/jsonpath/parse.go generated vendored Normal file
View File

@@ -0,0 +1,204 @@
package jsonpath
import (
"context"
"fmt"
"math"
"text/scanner"
"github.com/PaesslerAG/gval"
)
type parser struct {
*gval.Parser
path path
}
func parseRootPath(ctx context.Context, gParser *gval.Parser) (r gval.Evaluable, err error) {
p := newParser(gParser)
return p.parse(ctx)
}
func parseCurrentPath(ctx context.Context, gParser *gval.Parser) (r gval.Evaluable, err error) {
p := newParser(gParser)
p.appendPlainSelector(currentElementSelector())
return p.parse(ctx)
}
func newParser(p *gval.Parser) *parser {
return &parser{Parser: p, path: plainPath{}}
}
func (p *parser) parse(c context.Context) (r gval.Evaluable, err error) {
err = p.parsePath(c)
if err != nil {
return nil, err
}
return p.path.evaluate, nil
}
func (p *parser) parsePath(c context.Context) error {
switch p.Scan() {
case '.':
return p.parseSelect(c)
case '[':
keys, seperator, err := p.parseBracket(c)
if err != nil {
return err
}
switch seperator {
case ':':
if len(keys) > 3 {
return fmt.Errorf("range query has at least the parameter [min:max:step]")
}
keys = append(keys, []gval.Evaluable{
p.Const(0), p.Const(float64(math.MaxInt32)), p.Const(1)}[len(keys):]...)
p.appendAmbiguousSelector(rangeSelector(keys[0], keys[1], keys[2]))
case '?':
if len(keys) != 1 {
return fmt.Errorf("filter needs exactly one key")
}
p.appendAmbiguousSelector(filterSelector(keys[0]))
default:
if len(keys) == 1 {
p.appendPlainSelector(directSelector(keys[0]))
} else {
p.appendAmbiguousSelector(multiSelector(keys))
}
}
return p.parsePath(c)
case '(':
return p.parseScript(c)
default:
p.Camouflage("jsonpath", '.', '[', '(')
return nil
}
}
func (p *parser) parseSelect(c context.Context) error {
scan := p.Scan()
switch scan {
case scanner.Ident:
p.appendPlainSelector(directSelector(p.Const(p.TokenText())))
return p.parsePath(c)
case '.':
p.appendAmbiguousSelector(mapperSelector())
return p.parseMapper(c)
case '*':
p.appendAmbiguousSelector(starSelector())
return p.parsePath(c)
default:
return p.Expected("JSON select", scanner.Ident, '.', '*')
}
}
func (p *parser) parseBracket(c context.Context) (keys []gval.Evaluable, seperator rune, err error) {
for {
scan := p.Scan()
skipScan := false
switch scan {
case '?':
skipScan = true
case ':':
i := float64(0)
if len(keys) == 1 {
i = math.MaxInt32
}
keys = append(keys, p.Const(i))
skipScan = true
case '*':
if p.Scan() != ']' {
return nil, 0, p.Expected("JSON bracket star", ']')
}
return []gval.Evaluable{}, 0, nil
case ']':
if seperator == ':' {
skipScan = true
break
}
fallthrough
default:
p.Camouflage("jsonpath brackets")
key, err := p.ParseExpression(c)
if err != nil {
return nil, 0, err
}
keys = append(keys, key)
}
if !skipScan {
scan = p.Scan()
}
if seperator == 0 {
seperator = scan
}
switch scan {
case ':', ',':
case ']':
return
case '?':
if len(keys) != 0 {
return nil, 0, p.Expected("JSON filter", ']')
}
default:
return nil, 0, p.Expected("JSON bracket separator", ':', ',')
}
if seperator != scan {
return nil, 0, fmt.Errorf("mixed %v and %v in JSON bracket", seperator, scan)
}
}
}
func (p *parser) parseMapper(c context.Context) error {
scan := p.Scan()
switch scan {
case scanner.Ident:
p.appendPlainSelector(directSelector(p.Const(p.TokenText())))
case '[':
keys, seperator, err := p.parseBracket(c)
if err != nil {
return err
}
switch seperator {
case ':':
return fmt.Errorf("mapper can not be combined with range query")
case '?':
if len(keys) != 1 {
return fmt.Errorf("filter needs exactly one key")
}
p.appendAmbiguousSelector(filterSelector(keys[0]))
default:
p.appendAmbiguousSelector(multiSelector(keys))
}
case '*':
p.appendAmbiguousSelector(starSelector())
case '(':
return p.parseScript(c)
default:
return p.Expected("JSON mapper", '[', scanner.Ident, '*')
}
return p.parsePath(c)
}
func (p *parser) parseScript(c context.Context) error {
script, err := p.ParseExpression(c)
if err != nil {
return err
}
if p.Scan() != ')' {
return p.Expected("jsnopath script", ')')
}
p.appendPlainSelector(newScript(script))
return p.parsePath(c)
}
func (p *parser) appendPlainSelector(next plainSelector) {
p.path = p.path.withPlainSelector(next)
}
func (p *parser) appendAmbiguousSelector(next ambiguousSelector) {
p.path = p.path.withAmbiguousSelector(next)
}

103
server/vendor/github.com/PaesslerAG/jsonpath/path.go generated vendored Normal file
View File

@@ -0,0 +1,103 @@
package jsonpath
import "context"
type path interface {
evaluate(c context.Context, parameter interface{}) (interface{}, error)
visitMatchs(c context.Context, r interface{}, visit pathMatcher)
withPlainSelector(plainSelector) path
withAmbiguousSelector(ambiguousSelector) path
}
type plainPath []plainSelector
type ambiguousMatcher func(key, v interface{})
func (p plainPath) evaluate(ctx context.Context, root interface{}) (interface{}, error) {
return p.evaluatePath(ctx, root, root)
}
func (p plainPath) evaluatePath(ctx context.Context, root, value interface{}) (interface{}, error) {
var err error
for _, sel := range p {
value, err = sel(ctx, root, value)
if err != nil {
return nil, err
}
}
return value, nil
}
func (p plainPath) matcher(ctx context.Context, r interface{}, match ambiguousMatcher) ambiguousMatcher {
if len(p) == 0 {
return match
}
return func(k, v interface{}) {
res, err := p.evaluatePath(ctx, r, v)
if err == nil {
match(k, res)
}
}
}
func (p plainPath) visitMatchs(ctx context.Context, r interface{}, visit pathMatcher) {
res, err := p.evaluatePath(ctx, r, r)
if err == nil {
visit(nil, res)
}
}
func (p plainPath) withPlainSelector(selector plainSelector) path {
return append(p, selector)
}
func (p plainPath) withAmbiguousSelector(selector ambiguousSelector) path {
return &ambiguousPath{
parent: p,
branch: selector,
}
}
type ambiguousPath struct {
parent path
branch ambiguousSelector
ending plainPath
}
func (p *ambiguousPath) evaluate(ctx context.Context, parameter interface{}) (interface{}, error) {
matchs := []interface{}{}
p.visitMatchs(ctx, parameter, func(keys []interface{}, match interface{}) {
matchs = append(matchs, match)
})
return matchs, nil
}
func (p *ambiguousPath) visitMatchs(ctx context.Context, r interface{}, visit pathMatcher) {
p.parent.visitMatchs(ctx, r, func(keys []interface{}, v interface{}) {
p.branch(ctx, r, v, p.ending.matcher(ctx, r, visit.matcher(keys)))
})
}
func (p *ambiguousPath) branchMatcher(ctx context.Context, r interface{}, m ambiguousMatcher) ambiguousMatcher {
return func(k, v interface{}) {
p.branch(ctx, r, v, m)
}
}
func (p *ambiguousPath) withPlainSelector(selector plainSelector) path {
p.ending = append(p.ending, selector)
return p
}
func (p *ambiguousPath) withAmbiguousSelector(selector ambiguousSelector) path {
return &ambiguousPath{
parent: p,
branch: selector,
}
}
type pathMatcher func(keys []interface{}, match interface{})
func (m pathMatcher) matcher(keys []interface{}) ambiguousMatcher {
return func(key, match interface{}) {
m(append(keys, key), match)
}
}

View File

@@ -0,0 +1,181 @@
package jsonpath
import (
"bytes"
"context"
"fmt"
"strconv"
"text/scanner"
"github.com/PaesslerAG/gval"
)
type keyValueVisitor func(key string, value interface{})
type jsonObject interface {
visitElements(c context.Context, v interface{}, visit keyValueVisitor) error
}
type jsonObjectSlice []jsonObject
type keyValuePair struct {
key gval.Evaluable
value gval.Evaluable
}
type keyValueMatcher struct {
key gval.Evaluable
matcher func(c context.Context, r interface{}, visit pathMatcher)
}
func parseJSONObject(ctx context.Context, p *gval.Parser) (gval.Evaluable, error) {
evals := jsonObjectSlice{}
for {
switch p.Scan() {
default:
hasWildcard := false
p.Camouflage("object", ',', '}')
key, err := p.ParseExpression(context.WithValue(ctx, hasPlaceholdersContextKey{}, &hasWildcard))
if err != nil {
return nil, err
}
if p.Scan() != ':' {
if err != nil {
return nil, p.Expected("object", ':')
}
}
e, err := parseJSONObjectElement(ctx, p, hasWildcard, key)
if err != nil {
return nil, err
}
evals.addElements(e)
case ',':
case '}':
return evals.evaluable, nil
}
}
}
func parseJSONObjectElement(ctx context.Context, gParser *gval.Parser, hasWildcard bool, key gval.Evaluable) (jsonObject, error) {
if hasWildcard {
p := newParser(gParser)
switch gParser.Scan() {
case '$':
case '@':
p.appendPlainSelector(currentElementSelector())
default:
return nil, p.Expected("JSONPath key and value")
}
if err := p.parsePath(ctx); err != nil {
return nil, err
}
return keyValueMatcher{key, p.path.visitMatchs}, nil
}
value, err := gParser.ParseExpression(ctx)
if err != nil {
return nil, err
}
return keyValuePair{key, value}, nil
}
func (kv keyValuePair) visitElements(c context.Context, v interface{}, visit keyValueVisitor) error {
value, err := kv.value(c, v)
if err != nil {
return err
}
key, err := kv.key.EvalString(c, v)
if err != nil {
return err
}
visit(key, value)
return nil
}
func (kv keyValueMatcher) visitElements(c context.Context, v interface{}, visit keyValueVisitor) (err error) {
kv.matcher(c, v, func(keys []interface{}, match interface{}) {
key, er := kv.key.EvalString(context.WithValue(c, placeholdersContextKey{}, keys), v)
if er != nil {
err = er
}
visit(key, match)
})
return
}
func (j *jsonObjectSlice) addElements(e jsonObject) {
*j = append(*j, e)
}
func (j jsonObjectSlice) evaluable(c context.Context, v interface{}) (interface{}, error) {
vs := map[string]interface{}{}
err := j.visitElements(c, v, func(key string, value interface{}) { vs[key] = value })
if err != nil {
return nil, err
}
return vs, nil
}
func (j jsonObjectSlice) visitElements(ctx context.Context, v interface{}, visit keyValueVisitor) (err error) {
for _, e := range j {
if err := e.visitElements(ctx, v, visit); err != nil {
return err
}
}
return nil
}
func parsePlaceholder(c context.Context, p *gval.Parser) (gval.Evaluable, error) {
hasWildcard := c.Value(hasPlaceholdersContextKey{})
if hasWildcard == nil {
return nil, fmt.Errorf("JSONPath placeholder must only be used in an JSON object key")
}
*(hasWildcard.(*bool)) = true
switch p.Scan() {
case scanner.Int:
id, err := strconv.Atoi(p.TokenText())
if err != nil {
return nil, err
}
return placeholder(id).evaluable, nil
default:
p.Camouflage("JSONPath placeholder")
return allPlaceholders.evaluable, nil
}
}
type hasPlaceholdersContextKey struct{}
type placeholdersContextKey struct{}
type placeholder int
const allPlaceholders = placeholder(-1)
func (key placeholder) evaluable(c context.Context, v interface{}) (interface{}, error) {
wildcards, ok := c.Value(placeholdersContextKey{}).([]interface{})
if !ok || len(wildcards) <= int(key) {
return nil, fmt.Errorf("JSONPath placeholder #%d is not available", key)
}
if key == allPlaceholders {
sb := bytes.Buffer{}
sb.WriteString("$")
quoteWildcardValues(&sb, wildcards)
return sb.String(), nil
}
return wildcards[int(key)], nil
}
func quoteWildcardValues(sb *bytes.Buffer, wildcards []interface{}) {
for _, w := range wildcards {
if wildcards, ok := w.([]interface{}); ok {
quoteWildcardValues(sb, wildcards)
continue
}
sb.WriteString(fmt.Sprintf("[%v]",
strconv.Quote(fmt.Sprint(w)),
))
}
}

View File

@@ -0,0 +1,203 @@
package jsonpath
import (
"context"
"fmt"
"strconv"
"github.com/PaesslerAG/gval"
)
//plainSelector evaluate exactly one result
type plainSelector func(c context.Context, r, v interface{}) (interface{}, error)
//ambiguousSelector evaluate wildcard
type ambiguousSelector func(c context.Context, r, v interface{}, match ambiguousMatcher)
//@
func currentElementSelector() plainSelector {
return func(c context.Context, r, v interface{}) (interface{}, error) {
return c.Value(currentElement{}), nil
}
}
type currentElement struct{}
func currentContext(c context.Context, v interface{}) context.Context {
return context.WithValue(c, currentElement{}, v)
}
//.x, [x]
func directSelector(key gval.Evaluable) plainSelector {
return func(c context.Context, r, v interface{}) (interface{}, error) {
e, _, err := selectValue(c, key, r, v)
if err != nil {
return nil, err
}
return e, nil
}
}
// * / [*]
func starSelector() ambiguousSelector {
return func(c context.Context, r, v interface{}, match ambiguousMatcher) {
visitAll(v, func(key string, val interface{}) { match(key, val) })
}
}
// [x, ...]
func multiSelector(keys []gval.Evaluable) ambiguousSelector {
if len(keys) == 0 {
return starSelector()
}
return func(c context.Context, r, v interface{}, match ambiguousMatcher) {
for _, k := range keys {
e, wildcard, err := selectValue(c, k, r, v)
if err != nil {
continue
}
match(wildcard, e)
}
}
}
func selectValue(c context.Context, key gval.Evaluable, r, v interface{}) (value interface{}, jkey string, err error) {
c = currentContext(c, v)
switch o := v.(type) {
case []interface{}:
i, err := key.EvalInt(c, r)
if err != nil {
return nil, "", fmt.Errorf("could not select value, invalid key: %s", err)
}
if i < 0 || i >= len(o) {
return nil, "", fmt.Errorf("index %d out of bounds", i)
}
return o[i], strconv.Itoa(i), nil
case map[string]interface{}:
k, err := key.EvalString(c, r)
if err != nil {
return nil, "", fmt.Errorf("could not select value, invalid key: %s", err)
}
if r, ok := o[k]; ok {
return r, k, nil
}
return nil, "", fmt.Errorf("unknown key %s", k)
default:
return nil, "", fmt.Errorf("unsupported value type %T for select, expected map[string]interface{} or []interface{}", o)
}
}
//..
func mapperSelector() ambiguousSelector {
return mapper
}
func mapper(c context.Context, r, v interface{}, match ambiguousMatcher) {
match([]interface{}{}, v)
visitAll(v, func(wildcard string, v interface{}) {
mapper(c, r, v, func(key interface{}, v interface{}) {
match(append([]interface{}{wildcard}, key.([]interface{})...), v)
})
})
}
func visitAll(v interface{}, visit func(key string, v interface{})) {
switch v := v.(type) {
case []interface{}:
for i, e := range v {
k := strconv.Itoa(i)
visit(k, e)
}
case map[string]interface{}:
for k, e := range v {
visit(k, e)
}
}
}
//[? ]
func filterSelector(filter gval.Evaluable) ambiguousSelector {
return func(c context.Context, r, v interface{}, match ambiguousMatcher) {
visitAll(v, func(wildcard string, v interface{}) {
condition, err := filter.EvalBool(currentContext(c, v), r)
if err != nil {
return
}
if condition {
match(wildcard, v)
}
})
}
}
//[::]
func rangeSelector(min, max, step gval.Evaluable) ambiguousSelector {
return func(c context.Context, r, v interface{}, match ambiguousMatcher) {
cs, ok := v.([]interface{})
if !ok {
return
}
c = currentContext(c, v)
min, err := min.EvalInt(c, r)
if err != nil {
return
}
max, err := max.EvalInt(c, r)
if err != nil {
return
}
step, err := step.EvalInt(c, r)
if err != nil {
return
}
if min > max {
return
}
n := len(cs)
min = negmax(min, n)
max = negmax(max, n)
if step == 0 {
step = 1
}
if step > 0 {
for i := min; i < max; i += step {
match(strconv.Itoa(i), cs[i])
}
} else {
for i := max - 1; i >= min; i += step {
match(strconv.Itoa(i), cs[i])
}
}
}
}
func negmax(n, max int) int {
if n < 0 {
n = max + n
if n < 0 {
n = 0
}
} else if n > max {
return max
}
return n
}
// ()
func newScript(script gval.Evaluable) plainSelector {
return func(c context.Context, r, v interface{}) (interface{}, error) {
return script(currentContext(c, v), r)
}
}

15
server/vendor/github.com/PaesslerAG/jsonpath/test.sh generated vendored Normal file
View File

@@ -0,0 +1,15 @@
#!/bin/bash
# Script that runs tests, code coverage, and benchmarks all at once.
JSONPath_PATH=$HOME/gopath/src/github.com/PaesslerAG/jsonpath
# run the actual tests.
cd "${JSONPath_PATH}"
go test -bench=. -benchmem -coverprofile coverage.out
status=$?
if [ "${status}" != 0 ];
then
exit $status
fi