github.com/solo-io/cue@v0.4.7/internal/core/validate/validate.go (about)

     1  // Copyright 2020 CUE Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package validate collects errors from an evaluated Vertex.
    16  package validate
    17  
    18  import (
    19  	"github.com/solo-io/cue/internal/core/adt"
    20  )
    21  
    22  type Config struct {
    23  	// Concrete, if true, requires that all values be concrete.
    24  	Concrete bool
    25  
    26  	// DisallowCycles indicates that there may not be cycles.
    27  	DisallowCycles bool
    28  
    29  	// AllErrors continues descending into a Vertex, even if errors are found.
    30  	AllErrors bool
    31  
    32  	// TODO: omitOptional, if this is becomes relevant.
    33  }
    34  
    35  // Validate checks that a value has certain properties. The value must have
    36  // been evaluated.
    37  func Validate(ctx *adt.OpContext, v *adt.Vertex, cfg *Config) *adt.Bottom {
    38  	if cfg == nil {
    39  		cfg = &Config{}
    40  	}
    41  	x := validator{Config: *cfg, ctx: ctx}
    42  	x.validate(v)
    43  	return x.err
    44  }
    45  
    46  type validator struct {
    47  	Config
    48  	ctx          *adt.OpContext
    49  	err          *adt.Bottom
    50  	inDefinition int
    51  }
    52  
    53  func (v *validator) checkConcrete() bool {
    54  	return v.Concrete && v.inDefinition == 0
    55  }
    56  
    57  func (v *validator) add(b *adt.Bottom) {
    58  	if !v.AllErrors {
    59  		v.err = adt.CombineErrors(nil, v.err, b)
    60  		return
    61  	}
    62  	if !b.ChildError {
    63  		v.err = adt.CombineErrors(nil, v.err, b)
    64  	}
    65  }
    66  
    67  func (v *validator) validate(x *adt.Vertex) {
    68  	defer v.ctx.PopArc(v.ctx.PushArc(x))
    69  
    70  	if b, _ := x.BaseValue.(*adt.Bottom); b != nil {
    71  		switch b.Code {
    72  		case adt.CycleError:
    73  			if v.checkConcrete() || v.DisallowCycles {
    74  				v.add(b)
    75  			}
    76  
    77  		case adt.IncompleteError, adt.NotExistError:
    78  			if v.checkConcrete() {
    79  				v.add(b)
    80  			}
    81  
    82  		default:
    83  			v.add(b)
    84  		}
    85  		if !b.HasRecursive {
    86  			return
    87  		}
    88  
    89  	} else if v.checkConcrete() {
    90  		x = x.Default()
    91  		if !adt.IsConcrete(x) {
    92  			x := x.Value()
    93  			v.add(&adt.Bottom{
    94  				Code: adt.IncompleteError,
    95  				Err:  v.ctx.Newf("incomplete value %v", x),
    96  			})
    97  		}
    98  	}
    99  
   100  	for _, a := range x.Arcs {
   101  		if !v.AllErrors && v.err != nil {
   102  			break
   103  		}
   104  		if a.Label.IsRegular() {
   105  			v.validate(a)
   106  		} else {
   107  			v.inDefinition++
   108  			v.validate(a)
   109  			v.inDefinition--
   110  		}
   111  	}
   112  }