Skip to content

Commit

Permalink
pkg/encoding/yaml: hoist validate functionality
Browse files Browse the repository at this point in the history
We need to start passing OpContexts to
validate. We hoist the code to the internal yaml
package in preparation of that

This also removes an unwanted dependency on
pkg/encoding/yaml.

Issue #3649

Signed-off-by: Marcel van Lohuizen <[email protected]>
Change-Id: Ie57195a76707fa21ae1709ccb6cca55fd2bdde1e
Reviewed-on: https://cue.gerrithub.io/c/cue-lang/cue/+/1208005
Unity-Result: CUE porcuepine <[email protected]>
Reviewed-by: Matthew Sackman <[email protected]>
TryBot-Result: CUEcueckoo <[email protected]>
  • Loading branch information
mpvl committed Jan 30, 2025
1 parent 0eb0235 commit dc3e807
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 63 deletions.
4 changes: 1 addition & 3 deletions encoding/yaml/yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"cuelang.org/go/cue/ast"
cueyaml "cuelang.org/go/internal/encoding/yaml"
"cuelang.org/go/internal/source"
pkgyaml "cuelang.org/go/pkg/encoding/yaml"
)

// Extract parses the YAML specified by src to a CUE expression. If
Expand Down Expand Up @@ -97,7 +96,6 @@ func EncodeStream(iter cue.Iterator) ([]byte, error) {
// Validate validates the YAML and confirms it matches the constraints
// specified by v. For YAML streams, all values must match v.
func Validate(b []byte, v cue.Value) error {
// TODO(mvdan): encoding/yaml should not import pkg/encoding/yaml.
_, err := pkgyaml.Validate(b, v)
_, err := cueyaml.Validate(b, v)
return err
}
93 changes: 93 additions & 0 deletions internal/encoding/yaml/validate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// Copyright 2025 CUE Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package yaml

import (
"errors"
"io"

"cuelang.org/go/cue"
"cuelang.org/go/internal/pkg"
)

// Validate validates YAML and confirms it is an instance of schema.
// If the YAML source is a stream, every object must match v.
func Validate(b []byte, v cue.Value) (bool, error) {
d := NewDecoder("yaml.Validate", b)
r := v.Context()
for {
expr, err := d.Decode()
if err != nil {
if err == io.EOF {
return true, nil
}
return false, err
}

x := r.BuildExpr(expr)
if err := x.Err(); err != nil {
return false, err
}

// TODO: consider using subsumption again here.
// Alternatives:
// - allow definition of non-concrete list,
// like list.Of(int), or []int.
// - Introduce ! in addition to ?, allowing:
// list!: [...]
// if err := v.Subsume(inst.Value(), cue.Final()); err != nil {
// return false, err
// }
x = v.Unify(x)
if err := x.Err(); err != nil {
return false, err
}
if err := x.Validate(cue.Concrete(true)); err != nil {
// Strip error codes: incomplete errors are terminal in this case.
var b pkg.Bottomer
if errors.As(err, &b) {
err = b.Bottom().Err
}
return false, err
}
}
}

// ValidatePartial validates YAML and confirms it matches the constraints
// specified by v using unification. This means that b must be consistent with,
// but does not have to be an instance of v. If the YAML source is a stream,
// every object must match v.
func ValidatePartial(b []byte, v cue.Value) (bool, error) {
d := NewDecoder("yaml.ValidatePartial", b)
r := v.Context()
for {
expr, err := d.Decode()
if err != nil {
if err == io.EOF {
return true, nil
}
return false, err
}

x := r.BuildExpr(expr)
if err := x.Err(); err != nil {
return false, err
}

if x := v.Unify(x); x.Err() != nil {
return false, x.Err()
}
}
}
62 changes: 2 additions & 60 deletions pkg/encoding/yaml/manual.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (

"cuelang.org/go/cue"
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/errors"
cueyaml "cuelang.org/go/internal/encoding/yaml"
"cuelang.org/go/internal/pkg"
)
Expand Down Expand Up @@ -87,70 +86,13 @@ func UnmarshalStream(data []byte) (ast.Expr, error) {
// Validate validates YAML and confirms it is an instance of schema.
// If the YAML source is a stream, every object must match v.
func Validate(b []byte, v pkg.Schema) (bool, error) {
d := cueyaml.NewDecoder("yaml.Validate", b)
r := v.Context()
for {
expr, err := d.Decode()
if err != nil {
if err == io.EOF {
return true, nil
}
return false, err
}

x := r.BuildExpr(expr)
if err := x.Err(); err != nil {
return false, err
}

// TODO: consider using subsumption again here.
// Alternatives:
// - allow definition of non-concrete list,
// like list.Of(int), or []int.
// - Introduce ! in addition to ?, allowing:
// list!: [...]
// if err := v.Subsume(inst.Value(), cue.Final()); err != nil {
// return false, err
// }
x = v.Unify(x)
if err := x.Err(); err != nil {
return false, err
}
if err := x.Validate(cue.Concrete(true)); err != nil {
// Strip error codes: incomplete errors are terminal in this case.
var b pkg.Bottomer
if errors.As(err, &b) {
err = b.Bottom().Err
}
return false, err
}

}
return cueyaml.Validate(b, v)
}

// ValidatePartial validates YAML and confirms it matches the constraints
// specified by v using unification. This means that b must be consistent with,
// but does not have to be an instance of v. If the YAML source is a stream,
// every object must match v.
func ValidatePartial(b []byte, v pkg.Schema) (bool, error) {
d := cueyaml.NewDecoder("yaml.ValidatePartial", b)
r := v.Context()
for {
expr, err := d.Decode()
if err != nil {
if err == io.EOF {
return true, nil
}
return false, err
}

x := r.BuildExpr(expr)
if err := x.Err(); err != nil {
return false, err
}

if x := v.Unify(x); x.Err() != nil {
return false, x.Err()
}
}
return cueyaml.ValidatePartial(b, v)
}

0 comments on commit dc3e807

Please sign in to comment.