cuelang.org/go@v0.13.0/encoding/jsonschema/constraints.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  	"fmt"
    19  
    20  	"cuelang.org/go/cue"
    21  )
    22  
    23  type constraint struct {
    24  	key string
    25  
    26  	// phase indicates on which pass c constraint should be added. This ensures
    27  	// that constraints are applied in the correct order. For instance, the
    28  	// "required" constraint validates that a listed field is contained in
    29  	// "properties". For this to work, "properties" must be processed before
    30  	// "required" and thus must have a lower phase number than the latter.
    31  	phase int
    32  
    33  	// versions holds the versions for which this constraint is defined.
    34  	versions versionSet
    35  	fn       constraintFunc
    36  }
    37  
    38  // A constraintFunc converts a given JSON Schema constraint (specified in n)
    39  // to a CUE constraint recorded in state.
    40  type constraintFunc func(key string, n cue.Value, s *state)
    41  
    42  var constraintMap = map[string]*constraint{}
    43  
    44  func init() {
    45  	for _, c := range constraints {
    46  		if _, ok := constraintMap[c.key]; ok {
    47  			panic(fmt.Errorf("duplicate constraint entry for %q", c.key))
    48  		}
    49  		constraintMap[c.key] = c
    50  	}
    51  }
    52  
    53  // Note: the following table is ordered lexically by keyword name.
    54  // The various implementations are grouped by kind in the constraint-*.go files.
    55  
    56  const numPhases = 5
    57  
    58  // Note: OpenAPI is excluded from version sets by default, as it does not fit in
    59  // the linear progression of the rest of the JSON Schema versions.
    60  
    61  var constraints = []*constraint{
    62  	px("$anchor", constraintTODO, vfrom(VersionDraft2019_09)),
    63  	p2("$comment", constraintComment, vfrom(VersionDraft7)),
    64  	p2("$defs", constraintAddDefinitions, allVersions),
    65  	px("$dynamicAnchor", constraintTODO, vfrom(VersionDraft2020_12)),
    66  	px("$dynamicRef", constraintTODO, vfrom(VersionDraft2020_12)),
    67  	p1("$id", constraintID, vfrom(VersionDraft6)),
    68  	px("$recursiveAnchor", constraintTODO, vbetween(VersionDraft2019_09, VersionDraft2020_12)),
    69  	px("$recursiveRef", constraintTODO, vbetween(VersionDraft2019_09, VersionDraft2020_12)),
    70  	p2("$ref", constraintRef, allVersions|openAPI|k8sAPI),
    71  	p0("$schema", constraintSchema, allVersions),
    72  	px("$vocabulary", constraintTODO, vfrom(VersionDraft2019_09)),
    73  	p4("additionalItems", constraintAdditionalItems, vto(VersionDraft2019_09)),
    74  	p4("additionalProperties", constraintAdditionalProperties, allVersions|openAPILike),
    75  	p3("allOf", constraintAllOf, allVersions|openAPILike),
    76  	p3("anyOf", constraintAnyOf, allVersions|openAPILike),
    77  	p2("const", constraintConst, vfrom(VersionDraft6)),
    78  	p2("contains", constraintContains, vfrom(VersionDraft6)),
    79  	p2("contentEncoding", constraintContentEncoding, vfrom(VersionDraft7)),
    80  	p2("contentMediaType", constraintContentMediaType, vfrom(VersionDraft7)),
    81  	px("contentSchema", constraintTODO, vfrom(VersionDraft2019_09)),
    82  	p2("default", constraintDefault, allVersions|openAPILike),
    83  	p2("definitions", constraintAddDefinitions, allVersions),
    84  	p2("dependencies", constraintDependencies, allVersions),
    85  	px("dependentRequired", constraintTODO, vfrom(VersionDraft2019_09)),
    86  	px("dependentSchemas", constraintTODO, vfrom(VersionDraft2019_09)),
    87  	p2("deprecated", constraintDeprecated, vfrom(VersionDraft2019_09)|openAPI),
    88  	p2("description", constraintDescription, allVersions|openAPILike),
    89  	px("discriminator", constraintTODO, openAPI),
    90  	p1("else", constraintElse, vfrom(VersionDraft7)),
    91  	p2("enum", constraintEnum, allVersions|openAPILike),
    92  	px("example", constraintTODO, openAPILike),
    93  	p2("examples", constraintExamples, vfrom(VersionDraft6)),
    94  	p2("exclusiveMaximum", constraintExclusiveMaximum, allVersions|openAPILike),
    95  	p2("exclusiveMinimum", constraintExclusiveMinimum, allVersions|openAPILike),
    96  	px("externalDocs", constraintTODO, openAPILike),
    97  	p1("format", constraintFormat, allVersions|openAPILike),
    98  	p1("id", constraintID, vto(VersionDraft4)),
    99  	p1("if", constraintIf, vfrom(VersionDraft7)),
   100  	p2("items", constraintItems, allVersions|openAPILike),
   101  	p1("maxContains", constraintMaxContains, vfrom(VersionDraft2019_09)),
   102  	p2("maxItems", constraintMaxItems, allVersions|openAPILike),
   103  	p2("maxLength", constraintMaxLength, allVersions|openAPILike),
   104  	p2("maxProperties", constraintMaxProperties, allVersions|openAPILike),
   105  	p3("maximum", constraintMaximum, allVersions|openAPILike),
   106  	p1("minContains", constraintMinContains, vfrom(VersionDraft2019_09)),
   107  	p2("minItems", constraintMinItems, allVersions|openAPILike),
   108  	p2("minLength", constraintMinLength, allVersions|openAPILike),
   109  	p1("minProperties", constraintMinProperties, allVersions|openAPILike),
   110  	p3("minimum", constraintMinimum, allVersions|openAPILike),
   111  	p2("multipleOf", constraintMultipleOf, allVersions|openAPILike),
   112  	p3("not", constraintNot, allVersions|openAPILike),
   113  	p2("nullable", constraintNullable, openAPILike),
   114  	p3("oneOf", constraintOneOf, allVersions|openAPILike),
   115  	p2("pattern", constraintPattern, allVersions|openAPILike),
   116  	p3("patternProperties", constraintPatternProperties, allVersions),
   117  	p2("prefixItems", constraintPrefixItems, vfrom(VersionDraft2020_12)),
   118  	p2("properties", constraintProperties, allVersions|openAPILike),
   119  	p2("propertyNames", constraintPropertyNames, vfrom(VersionDraft6)),
   120  	px("readOnly", constraintTODO, vfrom(VersionDraft7)|openAPI),
   121  	p3("required", constraintRequired, allVersions|openAPILike),
   122  	p1("then", constraintThen, vfrom(VersionDraft7)),
   123  	p2("title", constraintTitle, allVersions|openAPILike),
   124  	p2("type", constraintType, allVersions|openAPILike),
   125  	px("unevaluatedItems", constraintTODO, vfrom(VersionDraft2019_09)),
   126  	px("unevaluatedProperties", constraintTODO, vfrom(VersionDraft2019_09)),
   127  	p2("uniqueItems", constraintUniqueItems, allVersions|openAPILike),
   128  	px("writeOnly", constraintTODO, vfrom(VersionDraft7)|openAPI),
   129  	px("xml", constraintTODO, openAPI),
   130  	p1("x-kubernetes-embedded-resource", constraintEmbeddedResource, k8s),
   131  	p1("x-kubernetes-group-version-kind", constraintGroupVersionKind, k8sAPI),
   132  	p2("x-kubernetes-int-or-string", constraintIntOrString, k8s),
   133  	px("x-kubernetes-list-map-keys", constraintIgnore, k8s),
   134  	px("x-kubernetes-list-type", constraintIgnore, k8s),
   135  	px("x-kubernetes-map-type", constraintIgnore, k8s),
   136  	px("x-kubernetes-patch-merge-key", constraintIgnore, k8s),
   137  	px("x-kubernetes-patch-strategy", constraintIgnore, k8s),
   138  	p2("x-kubernetes-preserve-unknown-fields", constraintPreserveUnknownFields, k8s),
   139  	px("x-kubernetes-validations", constraintTODO, k8s),
   140  }
   141  
   142  // px represents a TODO constraint that we haven't decided on a phase for yet.
   143  func px(name string, f constraintFunc, versions versionSet) *constraint {
   144  	return p1(name, f, versions)
   145  }
   146  
   147  func p0(name string, f constraintFunc, versions versionSet) *constraint {
   148  	return &constraint{key: name, phase: 0, versions: versions, fn: f}
   149  }
   150  
   151  func p1(name string, f constraintFunc, versions versionSet) *constraint {
   152  	return &constraint{key: name, phase: 1, versions: versions, fn: f}
   153  }
   154  
   155  func p2(name string, f constraintFunc, versions versionSet) *constraint {
   156  	return &constraint{key: name, phase: 2, versions: versions, fn: f}
   157  }
   158  
   159  func p3(name string, f constraintFunc, versions versionSet) *constraint {
   160  	return &constraint{key: name, phase: 3, versions: versions, fn: f}
   161  }
   162  
   163  func p4(name string, f constraintFunc, versions versionSet) *constraint {
   164  	return &constraint{key: name, phase: 4, versions: versions, fn: f}
   165  }