From ead3d317584f2ad356d2390d77de4fb974eddb33 Mon Sep 17 00:00:00 2001 From: "Henry H. Andrews" Date: Thu, 22 Sep 2022 12:47:33 -0700 Subject: [PATCH 1/2] "minContains"/"maxContains" to applicator vocab This moves the keywords with minamal changes to make sure the cross-referencing (which no longer goes between two documents) makes sense. A subsequent commit will fix the direction of the dependency. --- jsonschema-core.xml | 49 +++++++++++++++++++++++++++++++++- jsonschema-validation.xml | 55 +++++---------------------------------- meta/applicator.json | 9 +++++++ meta/validation.json | 5 ---- 4 files changed, 63 insertions(+), 55 deletions(-) diff --git a/jsonschema-core.xml b/jsonschema-core.xml index c0c7d99d..fa553d95 100644 --- a/jsonschema-core.xml +++ b/jsonschema-core.xml @@ -2122,7 +2122,7 @@ "contains", whose behavior is affected by the presence and value of - "minContains", in the Validation vocabulary + "minContains" @@ -2502,6 +2502,53 @@
+
+ + The value of this keyword MUST be a non-negative integer. + + + If "contains" is not present within the same schema object, + then this keyword has no effect. + + + An instance array or object is valid against "maxContains" in two ways, + depending on the form of the annotation result of an adjacent + "contains" keyword. The first way is if + the annotation result is an array and the length of that array is less than + or equal to the "maxContains" value. The second way is if the annotation + result is a boolean "true" and the instance length (number of items or + properties) is less than or equal to the "maxContains" value. + +
+ +
+ + The value of this keyword MUST be a non-negative integer. + + + If "contains" is not present within the same schema object, + then this keyword has no effect. + + + An instance array or object is valid against "minContains" in two ways, + depending on the form of the annotation result of an adjacent + "contains" keyword. The first way is if + the annotation result is an array and the length of that array is greater + than or equal to the "minContains" value. The second way is if the + annotation result is a boolean "true" and the instance length (number of + items or properties) is greater than or equal to the "minContains" value. + + + A value of 0 is allowed, but is only useful for setting a range + of occurrences from 0 to the value of "maxContains". A value of + 0 causes "minContains" and "contains" to always pass validation + (but validation can still fail against a "maxContains" keyword). + + + Omitting this keyword has the same behavior as a value of 1. + +
+
The value of this keyword MUST be a valid JSON Schema. diff --git a/jsonschema-validation.xml b/jsonschema-validation.xml index a8426471..390231e9 100644 --- a/jsonschema-validation.xml +++ b/jsonschema-validation.xml @@ -404,53 +404,6 @@ Omitting this keyword has the same behavior as a value of false.
- -
- - The value of this keyword MUST be a non-negative integer. - - - If "contains" is not present within the same schema object, - then this keyword has no effect. - - - An instance array or object is valid against "maxContains" in two ways, - depending on the form of the annotation result of an adjacent - "contains" keyword. The first way is if - the annotation result is an array and the length of that array is less than - or equal to the "maxContains" value. The second way is if the annotation - result is a boolean "true" and the instance length (number of items or - properties) is less than or equal to the "maxContains" value. - -
- -
- - The value of this keyword MUST be a non-negative integer. - - - If "contains" is not present within the same schema object, - then this keyword has no effect. - - - An instance array or object is valid against "minContains" in two ways, - depending on the form of the annotation result of an adjacent - "contains" keyword. The first way is if - the annotation result is an array and the length of that array is greater - than or equal to the "minContains" value. The second way is if the - annotation result is a boolean "true" and the instance length (number of - items or properties) is greater than or equal to the "minContains" value. - - - A value of 0 is allowed, but is only useful for setting a range - of occurrences from 0 to the value of "maxContains". A value of - 0 causes "minContains" and "contains" to always pass validation - (but validation can still fail against a "maxContains" keyword). - - - Omitting this keyword has the same behavior as a value of 1. - -
@@ -1368,8 +1321,8 @@
Several keywords have been moved from this document into the - Core Specification as of this draft, in some - cases with re-naming or other changes. This affects the following former + Core Specification starting with draft 2019-09, + in some cases with re-naming or other changes. This affects the following former validation keywords: @@ -1393,6 +1346,10 @@ For this reason, they are better defined as a generic mechanism on which validation, hyper-schema, and extension vocabularies can all be based. + + These keywords modify the behavior of "contains", and are therefore + grouped with it in the applicator vocabulary. + This keyword had two different modes of behavior, which made it relatively challenging to implement and reason about. diff --git a/meta/applicator.json b/meta/applicator.json index 1b2f8c2e..dbc0f68f 100644 --- a/meta/applicator.json +++ b/meta/applicator.json @@ -11,6 +11,11 @@ "properties": { "prefixItems": { "$ref": "#/$defs/schemaArray" }, "items": { "$dynamicRef": "#meta" }, + "maxContains": { "$ref": "#/$defs/nonNegativeInteger" }, + "minContains": { + "$ref": "#/$defs/nonNegativeInteger", + "default": 1 + }, "contains": { "$dynamicRef": "#meta" }, "additionalProperties": { "$dynamicRef": "#meta" }, "properties": { @@ -48,6 +53,10 @@ "not": { "$dynamicRef": "#meta" } }, "$defs": { + "nonNegativeInteger": { + "type": "integer", + "minimum": 0 + }, "schemaArray": { "type": "array", "minItems": 1, diff --git a/meta/validation.json b/meta/validation.json index 69d52e95..cdda94eb 100644 --- a/meta/validation.json +++ b/meta/validation.json @@ -53,11 +53,6 @@ "type": "boolean", "default": false }, - "maxContains": { "$ref": "#/$defs/nonNegativeInteger" }, - "minContains": { - "$ref": "#/$defs/nonNegativeInteger", - "default": 1 - }, "maxProperties": { "$ref": "#/$defs/nonNegativeInteger" }, "minProperties": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, "required": { "$ref": "#/$defs/stringArray" }, From 5c22b3085d3cafc92feb017b9ce1b1f0d5c13522 Mon Sep 17 00:00:00 2001 From: "Henry H. Andrews" Date: Thu, 22 Sep 2022 13:30:36 -0700 Subject: [PATCH 2/2] Reverse contains dependency per Karen Etheridge This fixes the problem where "minContains": 0 effectively un-failed "contains". The observable validation behavior is unchanged. Instead of "minContains" and "maxContains" reading annotations from "contains", "contains" reads annotations from "minContains" and "maxContains" and makes the only assertion decision. This solution was first proposed by Karen Etheridge. --- jsonschema-core.xml | 79 +++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 42 deletions(-) diff --git a/jsonschema-core.xml b/jsonschema-core.xml index fa553d95..33fb40fd 100644 --- a/jsonschema-core.xml +++ b/jsonschema-core.xml @@ -733,7 +733,7 @@ schema object.
-
+
A missing keyword MUST NOT produce a false assertion result, MUST NOT produce annotation results, and MUST NOT cause any other schema @@ -2507,17 +2507,12 @@ The value of this keyword MUST be a non-negative integer. - If "contains" is not present within the same schema object, - then this keyword has no effect. + This keyword modifies the behavior of "contains" within the same schema object, + as described below in the section for that keyword. - An instance array or object is valid against "maxContains" in two ways, - depending on the form of the annotation result of an adjacent - "contains" keyword. The first way is if - the annotation result is an array and the length of that array is less than - or equal to the "maxContains" value. The second way is if the annotation - result is a boolean "true" and the instance length (number of items or - properties) is less than or equal to the "maxContains" value. + Validation MUST always succeed against this keyword. + The value of this keyword is used as its annotation result.
@@ -2526,26 +2521,17 @@ The value of this keyword MUST be a non-negative integer. - If "contains" is not present within the same schema object, - then this keyword has no effect. + This keyword modifies the behavior of "contains" within the same schema object, + as described below in the section for that keyword. - An instance array or object is valid against "minContains" in two ways, - depending on the form of the annotation result of an adjacent - "contains" keyword. The first way is if - the annotation result is an array and the length of that array is greater - than or equal to the "minContains" value. The second way is if the - annotation result is a boolean "true" and the instance length (number of - items or properties) is greater than or equal to the "minContains" value. + Validation MUST always succeed against this keyword. + The value of this keyword is used as its annotation result. - - A value of 0 is allowed, but is only useful for setting a range - of occurrences from 0 to the value of "maxContains". A value of - 0 causes "minContains" and "contains" to always pass validation - (but validation can still fail against a "maxContains" keyword). - - - Omitting this keyword has the same behavior as a value of 1. + Per section , + omitted keywords MUST NOT produce annotation results. However, as described + in the section for "contains", the absence of this keyword's annotation + causes "contains" to assume a minimum value of 1.
@@ -2554,18 +2540,27 @@ The value of this keyword MUST be a valid JSON Schema. - An array instance is valid against "contains" if at least one of - its elements is valid against the given schema, - except when "minContains" is present and has a value of 0, in which - case an array instance MUST be considered valid against the "contains" keyword, - even if none of its elements is valid against the given schema. + This keyword applies its subschema to array elements or object property values. + + + An instance is valid against "contains" if the number of elements or property + values that are valid against its subschema is with the inclusive range of + the minimum and (if any) maximum number of occurrences. - An object instance is valid against "contains" if at least one of - its properties is valid against the given schema, - except when "minContains" is present and has a value of 0, in which - case an object instance MUST be considered valid against the "contains" keyword, - even if none of its property values is valid against the given schema. + The maximum number of occurrences is provided by the "maxContains" keyword + within the same schema object as "contains". If "maxContains" is absent, + the maximum number of occurrences MUST be unbounded. + + + The minimum number of occurrences is provided by the "minContains" keyword + within the same schema object as "contains". If "minContains" is absent, + the minimum number of occurrences MUST be 1. + + + Implementations MAY implement the dependency on "minContians" and + "maxContains" by inspecting their values rather than reading annotations + produced by those keywords. This keyword produces an annotation value which is an array of the @@ -2578,13 +2573,13 @@ This annotation affects the behavior of "unevaluatedItems" in the - Unevaluated vocabulary, and MAY also be used to implement the - "minContains" and "maxContains" keywords in the Validation vocabulary. + Unevaluated vocabulary. - The subschema MUST be applied to every array element even after the first - match has been found, in order to collect annotations for use by other - keywords. This is to ensure that all possible annotations are collected. + The subschema MUST be applied to every array element or object property + value even after the first match has been found, in order to collect + annotations for use by other keywords. This is to ensure that all possible + annotations are collected.