diff --git a/checker/checker_test.go b/checker/checker_test.go index e5691b76..fad56eb2 100644 --- a/checker/checker_test.go +++ b/checker/checker_test.go @@ -1077,6 +1077,9 @@ func TestCheck_types(t *testing.T) { "baz": types.String, }, }, + "arr": types.Array(types.StrictMap{ + "value": types.String, + }), } noerr := "no error" @@ -1090,6 +1093,8 @@ func TestCheck_types(t *testing.T) { {`foo.bar.unknown`, noerr}, {`[foo] | map(.unknown)`, `unknown field unknown`}, {`[foo] | map(.bar) | filter(.baz)`, `predicate should return boolean (got string)`}, + {`arr | filter(.value > 0)`, `invalid operation: > (mismatched types string and int)`}, + {`arr | filter(.value contains "a") | filter(.value == 0)`, `invalid operation: == (mismatched types string and int)`}, } for _, test := range tests { diff --git a/types/types.go b/types/types.go index e707e18c..71dc8b5a 100644 --- a/types/types.go +++ b/types/types.go @@ -28,6 +28,7 @@ var ( Nil = nilType{} ) +// Type is a type that can be used to represent a value. type Type interface { Nature() Nature } @@ -46,6 +47,8 @@ func (r rtype) Nature() Nature { return Nature{Type: r.t} } +// Map returns a type that represents a map of the given type. +// The map is not strict, meaning that it can contain keys not defined in the map. type Map map[string]Type func (m Map) Nature() Nature { @@ -59,6 +62,8 @@ func (m Map) Nature() Nature { return nt } +// StrictMap returns a type that represents a map of the given type. +// The map is strict, meaning that it can only contain keys defined in the map. type StrictMap map[string]Type func (m StrictMap) Nature() Nature { @@ -72,3 +77,21 @@ func (m StrictMap) Nature() Nature { } return nt } + +// Array returns a type that represents an array of the given type. +func Array(of Type) Type { + return array{of} +} + +type array struct { + of Type +} + +func (a array) Nature() Nature { + of := a.of.Nature() + return Nature{ + Type: reflect.TypeOf([]any{}), + Fields: make(map[string]Nature, 1), + ArrayOf: &of, + } +}