Skip to content

Commit

Permalink
Export lib type (#130)
Browse files Browse the repository at this point in the history
This PR exports the `lib` type (now `Lib`) so that the Buf CLI can call

```
cel.NewEnv(
    cel.Lib(celext.Lib{
        useUTC: useUTC,
    }),
)
```
without having to include the `cel.TypeDescs(protoregistry.GlobalFiles)`
option (which `celext.DefaultEnv` always include).

The Buf CLI does not want this option, here's an example to illustrate
this:

If I am working on `registry-proto` and I'm adding a field to
`buf.registry.module.v1.Module`, call it `foo` string, and I am also
adding a CEL rule on the message level, `this.foo != ''`.

Now I run `buf lint` and the CLI fails to compile this expression:

The linter tries to compile the expression in an env with
`cel.TypeDescs(protoregistry.GlobalFiles)`. Among these type descriptors
there already is a `buf.registry.module.v1.Module`, but this comes from
the generated Go type that the CLI depend on, not the `registry-proto`
I'm working on.
  • Loading branch information
oliversun9 authored Jul 5, 2024
1 parent 365d730 commit f204e44
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 15 deletions.
28 changes: 14 additions & 14 deletions celext/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func DefaultEnv(useUTC bool) (*cel.Env, error) {
// known to the application. They will otherwise fail with a runtime error
// if the type is unknown.
cel.TypeDescs(protoregistry.GlobalFiles),
cel.Lib(lib{
cel.Lib(Lib{
useUTC: useUTC,
}),
)
Expand All @@ -69,19 +69,19 @@ func RequiredCELEnvOptions(fieldDesc protoreflect.FieldDescriptor) []cel.EnvOpti
return nil
}

// lib is the collection of functions and settings required by protovalidate
// Lib is the collection of functions and settings required by protovalidate
// beyond the standard definitions of the CEL Specification:
//
// https://github.com/google/cel-spec/blob/master/doc/langdef.md#list-of-standard-definitions
//
// All implementations of protovalidate MUST implement these functions and
// should avoid exposing additional functions as they will not be portable.
type lib struct {
type Lib struct {
useUTC bool
}

//nolint:funlen
func (l lib) CompileOptions() []cel.EnvOption {
func (l Lib) CompileOptions() []cel.EnvOption {
return []cel.EnvOption{
cel.DefaultUTCTimeZone(l.useUTC),
cel.CrossTypeNumericComparisons(true),
Expand Down Expand Up @@ -354,15 +354,15 @@ func (l lib) CompileOptions() []cel.EnvOption {
}
}

func (l lib) ProgramOptions() []cel.ProgramOption {
func (l Lib) ProgramOptions() []cel.ProgramOption {
return []cel.ProgramOption{
cel.EvalOptions(
cel.OptOptimize,
),
}
}

func (l lib) uniqueMemberOverload(itemType *cel.Type, overload func(lister traits.Lister) ref.Val) cel.FunctionOpt {
func (l Lib) uniqueMemberOverload(itemType *cel.Type, overload func(lister traits.Lister) ref.Val) cel.FunctionOpt {
return cel.MemberOverload(
itemType.String()+"_unique_bool",
[]*cel.Type{cel.ListType(itemType)},
Expand All @@ -377,7 +377,7 @@ func (l lib) uniqueMemberOverload(itemType *cel.Type, overload func(lister trait
)
}

func (l lib) uniqueScalar(list traits.Lister) ref.Val {
func (l Lib) uniqueScalar(list traits.Lister) ref.Val {
size, ok := list.Size().Value().(int64)
if !ok {
return types.UnsupportedRefValConversionErr(list.Size().Value())
Expand All @@ -400,7 +400,7 @@ func (l lib) uniqueScalar(list traits.Lister) ref.Val {
// compares bytes type CEL values. This function is used instead of uniqueScalar
// as the bytes ([]uint8) type is not hashable in Go; we cheat this by converting
// the value to a string.
func (l lib) uniqueBytes(list traits.Lister) ref.Val {
func (l Lib) uniqueBytes(list traits.Lister) ref.Val {
size, ok := list.Size().Value().(int64)
if !ok {
return types.UnsupportedRefValConversionErr(list.Size().Value())
Expand All @@ -422,7 +422,7 @@ func (l lib) uniqueBytes(list traits.Lister) ref.Val {
return types.Bool(true)
}

func (l lib) validateEmail(addr string) bool {
func (l Lib) validateEmail(addr string) bool {
a, err := mail.ParseAddress(addr)
if err != nil || strings.ContainsRune(addr, '<') || a.Address != addr {
return false
Expand All @@ -437,7 +437,7 @@ func (l lib) validateEmail(addr string) bool {
return len(parts[0]) <= 64 && l.validateHostname(parts[1])
}

func (l lib) validateHostname(host string) bool {
func (l Lib) validateHostname(host string) bool {
if len(host) > 253 {
return false
}
Expand Down Expand Up @@ -465,7 +465,7 @@ func (l lib) validateHostname(host string) bool {
return !allDigits
}

func (l lib) validateIP(addr string, ver int64) bool {
func (l Lib) validateIP(addr string, ver int64) bool {
address := net.ParseIP(addr)
if address == nil {
return false
Expand All @@ -482,7 +482,7 @@ func (l lib) validateIP(addr string, ver int64) bool {
}
}

func (l lib) validateIPPrefix(p string, ver int64, strict bool) bool {
func (l Lib) validateIPPrefix(p string, ver int64, strict bool) bool {
prefix, err := netip.ParsePrefix(p)
if err != nil {
return false
Expand All @@ -502,7 +502,7 @@ func (l lib) validateIPPrefix(p string, ver int64, strict bool) bool {
}
}

func (l lib) isHostAndPort(val string, portRequired bool) bool {
func (l Lib) isHostAndPort(val string, portRequired bool) bool {
if len(val) == 0 {
return false
}
Expand Down Expand Up @@ -533,7 +533,7 @@ func (l lib) isHostAndPort(val string, portRequired bool) bool {
l.validatePort(port)
}

func (l lib) validatePort(val string) bool {
func (l Lib) validatePort(val string) bool {
n, err := strconv.ParseUint(val, 10, 32)
return err == nil && n <= 65535
}
2 changes: 1 addition & 1 deletion celext/lib_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (
func TestCELLib(t *testing.T) {
t.Parallel()

env, err := cel.NewEnv(cel.Lib(lib{}))
env, err := cel.NewEnv(cel.Lib(Lib{}))
require.NoError(t, err)

t.Run("ext", func(t *testing.T) {
Expand Down

0 comments on commit f204e44

Please sign in to comment.