cuelang.org/go@v0.10.1/encoding/jsonschema/constraints_combinator.go (about)

     1  // Copyright 2019 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 jsonschema
    16  
    17  import (
    18  	"cuelang.org/go/cue"
    19  	"cuelang.org/go/cue/ast"
    20  	"cuelang.org/go/cue/token"
    21  )
    22  
    23  // Constraint combinators.
    24  
    25  func constraintAllOf(key string, n cue.Value, s *state) {
    26  	var a []ast.Expr
    27  	var knownTypes cue.Kind
    28  	for _, v := range s.listItems("allOf", n, false) {
    29  		x, sub := s.schemaState(v, s.allowedTypes, nil, true)
    30  		s.allowedTypes &= sub.allowedTypes
    31  		if sub.hasConstraints() {
    32  			// This might seem a little odd, since the actual
    33  			// types are the intersection of the known types
    34  			// of the allOf members. However, knownTypes
    35  			// is really there to avoid adding redundant disjunctions.
    36  			// So if we have (int & string) & (disjunction)
    37  			// we definitely don't have to add int or string to
    38  			// disjunction.
    39  			knownTypes |= sub.knownTypes
    40  			a = append(a, x)
    41  		}
    42  	}
    43  	// TODO maybe give an error/warning if s.allowedTypes == 0
    44  	// as that's a known-impossible assertion?
    45  	if len(a) > 0 {
    46  		s.knownTypes &= knownTypes
    47  		s.all.add(n, ast.NewBinExpr(token.AND, a...))
    48  	}
    49  }
    50  
    51  func constraintAnyOf(key string, n cue.Value, s *state) {
    52  	var types cue.Kind
    53  	var a []ast.Expr
    54  	var knownTypes cue.Kind
    55  	for _, v := range s.listItems("anyOf", n, false) {
    56  		x, sub := s.schemaState(v, s.allowedTypes, nil, true)
    57  		types |= sub.allowedTypes
    58  		knownTypes |= sub.knownTypes
    59  		a = append(a, x)
    60  	}
    61  	s.allowedTypes &= types
    62  	if len(a) > 0 {
    63  		s.knownTypes &= knownTypes
    64  		s.all.add(n, ast.NewBinExpr(token.OR, a...))
    65  	}
    66  }
    67  
    68  func constraintOneOf(key string, n cue.Value, s *state) {
    69  	var types cue.Kind
    70  	var knownTypes cue.Kind
    71  	var a []ast.Expr
    72  	hasSome := false
    73  	for _, v := range s.listItems("oneOf", n, false) {
    74  		x, sub := s.schemaState(v, s.allowedTypes, nil, true)
    75  		types |= sub.allowedTypes
    76  
    77  		// TODO: make more finegrained by making it two pass.
    78  		if sub.hasConstraints() {
    79  			hasSome = true
    80  		}
    81  
    82  		if !isAny(x) {
    83  			knownTypes |= sub.knownTypes
    84  			a = append(a, x)
    85  		}
    86  	}
    87  	// TODO if there are no elements in the oneOf, validation
    88  	// should fail.
    89  	s.allowedTypes &= types
    90  	if len(a) > 0 && hasSome {
    91  		s.knownTypes &= knownTypes
    92  		s.all.add(n, ast.NewBinExpr(token.OR, a...))
    93  	}
    94  
    95  	// TODO: oneOf({a:x}, {b:y}, ..., not(anyOf({a:x}, {b:y}, ...))),
    96  	// can be translated to {} | {a:x}, {b:y}, ...
    97  }