From 53ca0af016aba3b04196559034fbf9890cdf4473 Mon Sep 17 00:00:00 2001 From: Henry Andrews Date: Wed, 30 Sep 2020 23:20:28 -0700 Subject: [PATCH] Add vocabulary files and keyword dependencies. This just covers the Core spec, the rest will be done as a follow-on. --- jsonschema-core.xml | 229 ++++++++++++++++++++++++++++++++--------- vocab/applicator.json | 42 ++++++++ vocab/core.json | 18 ++++ vocab/unevaluated.json | 23 +++++ 4 files changed, 264 insertions(+), 48 deletions(-) create mode 100644 vocab/applicator.json create mode 100644 vocab/core.json create mode 100644 vocab/unevaluated.json diff --git a/jsonschema-core.xml b/jsonschema-core.xml index 93638219..f81a3e14 100644 --- a/jsonschema-core.xml +++ b/jsonschema-core.xml @@ -687,14 +687,74 @@
- Keyword behavior MAY be defined in terms of the annotation results - of subschemas and/or adjacent keywords - (keywords within the same schema object) and their subschemas. + Keyword behavior MAY be defined in terms of the annotation or + validation results of adjacent keywords (keywords within the same + schema object) and their subschemas. Such keywords MUST NOT result in a circular dependency. Keywords MAY modify their behavior based on the presence or absence of another keyword in the same schema object. + + Keywords MAY specify dependencies on keywords in other vocabularies. + However, dependencies are purely in terms of keyword/annotation name. + While a keyword's description SHOULD indicate the vocabulary that is + expected to provide the dependency, this is not an enforceable dependency. + As with overlapping keyword names in general, the behavior of using + vocabularies with incompatible semantics is undefined. + + + In addition to depending on specific adjacent keywords, a keyword MAY + depend on specific annotations collected through any and all in-place applicators, + without needing to list individual in-place applicator keywords. This allows + for continued correct behavior when some other vocabulary adds previously unknown + in-place applicators. An annotation that has been collected through in-place + applicators will have the same instance location as that which is currently + being processed. + + At this time, the only class of keywords that can be depended upon like this + are in-place applicators. To date, no use cases have been found for other + keyword class dependencies. This could change in the future. + + + + Keywords defining interactions through these mechanisms SHOULD be supported by any + vocabulary plugin architecture; interactions of this sort involving adjacent + keywords and in-place applicators are expressed in machine-readable form in the + vocabulary file. + + + Vocabulary authors MUST NOT assume that vocabulary plug-in architectures + will allow any other form of interaction. Save for explicit agreement, + schema authors SHALL NOT expect these keywords depending on additional + interactions to be supported by peer implementations. + +
+ + While keyword interactions MUST be defined as described above in order + to be implementable in any conforming plugin architecture, implementations + MAY choose other ways to implement specific keyword dependencies for + reasons of performance or simplicity. + + + Because annotation collection can add significant cost in terms of both + computation and memory, implementations MAY opt out of this feature. + Keywords that are specified in terms of collected annotations SHOULD + describe reasonable alternate approaches when appropriate. + This approach is demonstrated by the + "" and + "" keywords in this + document. However, "" + and "" do not + specify alternate approaches, as the complexity of those keywords + is not conducive to simple alternatives. + + + Note that when no such alternate approach is possible for a keyword, + implementations that do not support annotation collection will not + be able to support those keywords or vocabularies that contain them. + +
@@ -712,21 +772,6 @@ produces the default behavior would produce annotation results if present, the default behavior still MUST NOT result in annotations. - - Because annotation collection can add significant cost in terms of both - computation and memory, implementations MAY opt out of this feature. - Keywords that are specified in terms of collected annotations SHOULD - describe reasonable alternate approaches when appropriate. - This approach is demonstrated by the - "" and - "" keywords in this - document. - - - Note that when no such alternate approach is possible for a keyword, - implementations that do not support annotation collections will not - be able to support those keywords or vocabularies that contain them. -
@@ -1111,7 +1156,7 @@ The current URI for the Core vocabulary is: - <https://json-schema.org/draft/2019-09/vocab/core>. + . The current URI for the corresponding meta-schema is: @@ -1292,6 +1337,122 @@
+
+ + The vocabulary file is a machine-readable specification of + essential information that a vocabulary plugin system would + need to know to support keyword interactions. It allows + the implementation to evaluate keywords in the correct order + across all vocabularies. + + + This draft introduces a minimal format based on preliminary feedback. + Its format may change substantially in the next draft as more + feedback comes in. However, the capabilities it is currently able + to describe are expected ot remain, even if the syntax changes. + + + The vocabulary file MUST be a JSON document consisting + of a single object with two properties: + + + The value of this keyword MUST be an absolute-URI, + which MUST be the URI expected to be used in the + "$vocabulary" keyword in a meta-schema; as noted + in the "$vocabulary" description, this URI is an + identifier rather than a locator + + + An object whose keys MUST be the complete set + of keywords defined by this vocabulary, and whose + values MUST be objects as defined below + + + The per-keyword object MAY be empty, or MAY have any of the following + properties: + + + The value of this property MUST be a boolean; if true, the + keyword is an in-place applicator; if false (the default) + it is some other unspecified classification + + + The value of this property MUST be an array of strings; + the strings MUST be names of the annotations (which are the + same as the keywords that produce them) on which this keyword's + behavior depends; the annotations/keywords need not be defined + in this same vocabulary; the default is an empty array + + + The value of this property MUST be a boolean; if true, + the keyword depends on the annotations listed in "dependsOn" + both from adjacent keywords, and from annotations attached to + the current instance location that are collected through + adjacent in-place applicator keywords; if false (the default), + only annotations collected directly from adjacent keywords are used + + + The value of this property MUST be an object; the property + names MUST be names of keywords, and the property values MUST + be booleans, such that this keyword MUST be evaluated only if + the keywords in this object are present as adjacent keywords, + and produce an assertion result equal to the property value + + + + + Note that when using "throughInPlaceApplicators", a keyword may depend + on itself, as it may appear in in-place applicator subschemas. + When examining adjacent keywords, implementations MUST detect such + a self-dependency and avoid deadlocking. + + +
+ + The following example set of keywords, taken from other vocabularies + in this specification, demonstrate all of the above possibilities: + + + + +
+
+
@@ -2086,7 +2247,7 @@ The current URI for this vocabulary, known as the Applicator vocabulary, is: - <https://json-schema.org/draft/2019-09/vocab/applicator>. + . The current URI for the corresponding meta-schema is: @@ -2099,34 +2260,6 @@ before the next to indicate the same syntax and semantics as those listed here. -
- - Schema keywords typically operate independently, without - affecting each other's outcomes. - - - For schema author convenience, there are some exceptions among the - keywords in this vocabulary: - - - "additionalProperties", whose behavior is defined in terms of - "properties" and "patternProperties" - - - "unevaluatedProperties", whose behavior is defined in terms of - annotations from "properties", "patternProperties", - "additionalProperties" and itself - - - "items", whose behavior is defined in terms of "prefixItems" - - - "unevaluatedItems", whose behavior is defined in terms of annotations - from "prefixItems", "items", "contains", and itself - - - -
diff --git a/vocab/applicator.json b/vocab/applicator.json new file mode 100644 index 00000000..3aff8265 --- /dev/null +++ b/vocab/applicator.json @@ -0,0 +1,42 @@ +{ + "vocabulary": "https://json-schema.org/draft/next/vocab/applicator", + "keywords": { + "allOf": { + "inPlaceApplicator": true + }, + "anyOf": { + "inPlaceApplicator": true + }, + "oneOf": { + "inPlaceApplicator": true + }, + "not": { + "inPlaceApplicator": true + }, + "if": { + "inPlaceApplicator": true + }, + "then": { + "inPlaceApplicator": true, + "dependsOnValidity": {"if": true} + }, + "else": { + "inPlaceApplicator": true, + "dependsOnValidity": {"if": false} + }, + "dependentSchemas": { + "inPlaceApplicator": true + }, + "prefixItems": {}, + "items": { + "dependsOn": ["prefixItems"] + }, + "contains": {}, + "properties": {}, + "patternProperties": {}, + "additionalProperties": { + "dependsOn": ["properties", "patternProperties"] + }, + "propertyNames": {} + } +} diff --git a/vocab/core.json b/vocab/core.json new file mode 100644 index 00000000..7fe2b7b7 --- /dev/null +++ b/vocab/core.json @@ -0,0 +1,18 @@ +{ + "vocabulary": "https://json-schema.org/draft/next/vocab/core", + "keywords": { + "$schema": {}, + "$vocabulary": {}, + "$id": {}, + "$anchor": {}, + "$ref": { + "inPlaceApplicator": true + }, + "$dynamicAnchor": {}, + "$dynamicRef": { + "inPlaceApplicator": true + }, + "$defs": {}, + "$comment": {} + } +} diff --git a/vocab/unevaluated.json b/vocab/unevaluated.json new file mode 100644 index 00000000..d59baa1f --- /dev/null +++ b/vocab/unevaluated.json @@ -0,0 +1,23 @@ +{ + "vocabulary": "https://json-schema.org/draft/next/vocab/unevaluated", + "keywords": { + "unevaluatedItems": { + "dependsOn": [ + "prefixItems", + "items", + "contains", + "unevaluatedItems" + ], + "throughInPlaceApplicators": true + }, + "unevaluatedProperties": { + "dependsOn": [ + "properties", + "patternProperties", + "additionalProperties", + "unevaluatedProperties" + ], + "throughInPlaceApplicators": true + } + } +}