From c86157ccfb7b3e995632acf5bdbc77b788cd05ca Mon Sep 17 00:00:00 2001 From: Henry Andrews Date: Thu, 14 May 2020 23:51:04 -0700 Subject: [PATCH 01/10] Rename "$recursive*" to "$dynamic*" Preliminary work for revamping these keywords. --- jsonschema-core.xml | 96 ++++++++++++++++++++++----------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/jsonschema-core.xml b/jsonschema-core.xml index d25b23ee..b767736f 100644 --- a/jsonschema-core.xml +++ b/jsonschema-core.xml @@ -625,7 +625,7 @@ URI-reference or a full URI, which is found through the lexical structure of the JSON document. The "$id" core keyword and the "base" JSON Hyper-Schema keyword are examples of this sort - of behavior. Additionally, "$ref" and "$recursiveRef" from + of behavior. Additionally, "$ref" and "$dyanmicRef" from this specification resolve their values in this way, although they do not change how further values are resolved. @@ -640,12 +640,12 @@ with an instance document. The outermost dynamic scope is the root schema of the schema document in which processing begins. The path from this root schema to any particular keyword (that - includes any "$ref" and "$recursiveRef" keywords that may have + includes any "$ref" and "$dyanmicRef" keywords that may have been resolved) is considered the keyword's "validation path." Or should this be the schema object at which processing begins, even if it is not a root? This has some implications - for the case where "$recursiveAnchor" is only allowed in the + for the case where "$dyanmicAnchor" is only allowed in the root schema but processing begins in a subschema. @@ -660,8 +660,8 @@ dynamic parent, rather than examining the local lexically enclosing parent. - The concept of dynamic scope is primarily used with "$recursiveRef" and - "$recursiveAnchor", and should be considered an advanced feature + The concept of dynamic scope is primarily used with "$dyanmicRef" and + "$dyanmicAnchor", and should be considered an advanced feature and used with caution when defining additional keywords. It also appears when reporting errors and collected annotations, as it may be possible to revisit the same lexical scope repeatedly with different dynamic @@ -723,8 +723,8 @@ While custom identifier keywords are possible, vocabulary designers should take care not to disrupt the functioning of core keywords. For example, - the "$recursiveAnchor" keyword in this specification limits its URI resolution - effects to the matching "$recursiveRef" keyword, leaving "$ref" undisturbed. + the "$dyanmicAnchor" keyword in this specification limits its URI resolution + effects to the matching "$dyanmicRef" keyword, leaving "$ref" undisturbed.
@@ -775,7 +775,7 @@ For some by-reference applicators, such as "$ref", the referenced schema can be determined by static analysis of the schema document's lexical scope. Others, - such as "$recursiveRef" and "$recursiveAnchor", may make use of dynamic + such as "$dyanmicRef" and "$dyanmicAnchor", may make use of dynamic scoping, and therefore only be resolvable in the process of evaluating the schema with an instance. @@ -1416,13 +1416,13 @@
Several keywords can be used to reference a schema which is to be applied to the - current instance location. "$ref" and "$recursiveRef" are applicator - keywords, applying the referenced schema to the instance. "$recursiveAnchor" + current instance location. "$ref" and "$dyanmicRef" are applicator + keywords, applying the referenced schema to the instance. "$dyanmicAnchor" is an identifier keyword that controls how the base URI for resolving - the URI-reference value of "$recursiveRef is determined. + the URI-reference value of "$dyanmicRef is determined. - As the values of "$ref" and "$recursiveRef" are URI References, this allows + As the values of "$ref" and "$dynamicRef" are URI References, this allows the possibility to externalise or divide a schema across multiple files, and provides the ability to validate recursive structures through self-reference. @@ -1451,21 +1451,21 @@
-
+
- The "$recursiveRef" and "$recursiveAnchor" keywords are used to construct + The "$dyanmicRef" and "$dyanmicAnchor" keywords are used to construct extensible recursive schemas. A recursive schema is one that has a reference to its own root, identified by the empty fragment URI reference ("#"). - Simply stated, a "$recursiveRef" behaves identically to "$ref", except - when its target schema contains "$recursiveAnchor" with a value of true. + Simply stated, a "$dynamicRef" behaves identically to "$ref", except + when its target schema contains "$dynamicAnchor" with a value of true. In that case, the dynamic scope is examined to determine a new base URI, - and the URI-reference in "$recursiveRef" is re-evaluated against that + and the URI-reference in "$dynamicRef" is re-evaluated against that base URI. Unlike base URI changes with "$id", changes with - "$recursiveAnchor" are calculated each time a "$recursiveRef" is + "$dynamicAnchor" are calculated each time a "$dynamicRef" is resolved, and do not impact any other keywords. @@ -1477,9 +1477,9 @@ of these keywords. -
+
- The value of the "$recursiveRef" property MUST be a string which is + The value of the "$dynamicRef" property MUST be a string which is a URI-reference. It is a by-reference applicator that uses a dynamically calculated base URI to resolve its value. @@ -1492,22 +1492,22 @@ - The value of "$recursiveRef" is initially resolved against the + The value of "$dynamicRef" is initially resolved against the current base URI, in the same manner as for "$ref". The schema identified by the resulting URI is examined for the - presence of "$recursiveAnchor", and a new base URI is calculated + presence of "$dynamicAnchor", and a new base URI is calculated as described for that keyword in the following section. - Finally, the value of "$recursiveRef" is resolved against the - new base URI determined according to "$recursiveAnchor" producing + Finally, the value of "$dynamicRef" is resolved against the + new base URI determined according to "$dynamicAnchor" producing the final resolved reference URI. - Note that in the absence of "$recursiveAnchor" (and in some cases - when it is present), "$recursiveRef"'s behavior is identical to + Note that in the absence of "$dynamicAnchor" (and in some cases + when it is present), "$dynamicRef"'s behavior is identical to that of "$ref". @@ -1515,22 +1515,22 @@ referenced schema.
-
+
- The value of the "$recursiveAnchor" property MUST be a boolean. + The value of the "$dynamicAnchor" property MUST be a boolean. - "$recursiveAnchor" is used to dynamically identify a base URI - at runtime for "$recursiveRef" by marking where such a calculation + "$dynamicAnchor" is used to dynamically identify a base URI + at runtime for "$dynamicRef" by marking where such a calculation can start, and where it stops. This keyword MUST NOT affect the base URI of other keywords, unless they are explicitly defined to rely on it. If set to true, then when the containing schema object is used - as a target of "$recursiveRef", a new base URI is determined + as a target of "$dynamicRef", a new base URI is determined by examining the dynamic scope for - the outermost schema that also contains "$recursiveAnchor" + the outermost schema that also contains "$dynamicAnchor" with a value of true. The base URI of that schema is then used as the dynamic base URI. @@ -2670,7 +2670,7 @@ The relative location of the validating keyword that follows the validation path. The value MUST be expressed as a JSON Pointer, and it MUST include - any by-reference applicators such as "$ref" or "$recursiveRef". + any by-reference applicators such as "$ref" or "$dynamicRef".
@@ -2693,7 +2693,7 @@ The absolute, dereferenced location of the validating keyword. The value MUST be expressed as an absolute URI using the canonical URI of the relevant schema object, and it MUST NOT include by-reference applicators - such as "$ref" or "$recursiveRef" as non-terminal path components. + such as "$ref" or "$dynamicRef" as non-terminal path components. It MAY end in such keywords if the error or annotation is for that keyword, such as an unresolvable reference. @@ -3461,7 +3461,7 @@ https://example.com/schemas/common#/$defs/count/minimum { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "https://example.com/tree", - "$recursiveAnchor": true, + "$dynamicAnchor": true, "type": "object", "properties": { @@ -3469,7 +3469,7 @@ https://example.com/schemas/common#/$defs/count/minimum "children": { "type": "array", "items": { - "$recursiveRef": "#" + "$dynamicRef": "#" } } } @@ -3479,7 +3479,7 @@ https://example.com/schemas/common#/$defs/count/minimum { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "https://example.com/strict-tree", - "$recursiveAnchor": true, + "$dynamicAnchor": true, "$ref": "tree", "unevaluatedProperties": false @@ -3495,23 +3495,23 @@ https://example.com/schemas/common#/$defs/count/minimum If we apply the "strict-tree" schema to the instance, we will follow the "$ref" to the "tree" schema, examine its "children" subschema, - and find the "$recursiveAnchor" in its "items" subschema. + and find the "$dynamicAnchor" in its "items" subschema. At this point, the dynamic path is - "#/$ref/properties/children/items/$recursiveRef". + "#/$ref/properties/children/items/$dynamicRef". The base URI at this point is "https://example.com/tree", so the - "$recursiveRef" initially resolves to "https://example.com/tree#". - Since "$recursiveAnchor" is true, we examine the dynamic path to + "$dynamicRef" initially resolves to "https://example.com/tree#". + Since "$dynamicAnchor" is true, we examine the dynamic path to see if there is a different base URI to use. We find - "$recursiveAnchor" with a true value at the dynamic paths of + "$dynamicAnchor" with a true value at the dynamic paths of "#" and "#/$ref". The outermost is "#", which is the root schema of the "strict-tree" schema, so we use its base URI of "https://example.com/strict-tree", which produces a final resolved URI of - "https://example.com/strict-tree#" for the "$recursiveRef". + "https://example.com/strict-tree#" for the "$dynamicRef". This way, the recursion in the "tree" schema recurses to the root @@ -3560,8 +3560,8 @@ https://example.com/schemas/common#/$defs/count/minimum appropriate for certain use cases. - The recursive nature of meta-schemas makes the "$recursiveAnchor" - and "$recursiveRef" keywords particularly useful for extending + The recursive nature of meta-schemas makes the "$dynamicAnchor" + and "$dynamicRef" keywords particularly useful for extending existing meta-schemas, as can be seen in the JSON Hyper-Schema meta-schema which extends the Validation meta-schema. @@ -3617,7 +3617,7 @@ https://example.com/schemas/common#/$defs/count/minimum { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "https://example.com/meta/general-use-example", - "$recursiveAnchor": true, + "$dynamicAnchor": true, "$vocabulary": { "https://json-schema.org/draft/2019-09/vocab/core": true, "https://json-schema.org/draft/2019-09/vocab/applicator": true, @@ -3652,7 +3652,7 @@ https://example.com/schemas/common#/$defs/count/minimum { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "https://example.com/meta/example-vocab", - "$recursiveAnchor": true, + "$dynamicAnchor": true, "$vocabulary": { "https://example.com/vocab/example-vocab": true, }, From 940586a1cb790dd56faaea1521f632d3d124685a Mon Sep 17 00:00:00 2001 From: Henry Andrews Date: Mon, 11 May 2020 15:45:11 -0700 Subject: [PATCH 02/10] $dynamicAnchor creates fragment, no base URI stuff Instead of using a boolean (which never really fit with how the similarly named "$anchor" worked, and meant only one dynamic resolution was possible at a time) and messing with base URIs and re-resolving URI-references (a topic that creates plenty of confusion even on its own), use a fragment name the same as "$anchor" and make "$dynamicRef" work by just looking for the outermost resource with a matching "$dynamicAnchor" fragment name. This stil requires that the initial "$dynamicRef" target URI be a valid URI, with a fragment created by "$dynamicAnchor", in order to produce the dynamic behavior. This ensures that it is always clear which schemas are dynamic extension points and which are not. --- jsonschema-core.xml | 179 +++++++++++++++++++------------------------- 1 file changed, 76 insertions(+), 103 deletions(-) diff --git a/jsonschema-core.xml b/jsonschema-core.xml index b767736f..63f56be8 100644 --- a/jsonschema-core.xml +++ b/jsonschema-core.xml @@ -623,11 +623,9 @@ Keywords MAY be defined with a partial value, such as a URI-reference, which must be resolved against another value, such as another URI-reference or a full URI, which is found through the lexical - structure of the JSON document. The "$id" core keyword and - the "base" JSON Hyper-Schema keyword are examples of this sort - of behavior. Additionally, "$ref" and "$dyanmicRef" from - this specification resolve their values in this way, although - they do not change how further values are resolved. + structure of the JSON document. The "$id", "$ref", and + "$dyanmicRef" core keywords, and the "base" JSON Hyper-Schema + keyword, are examples of this sort of behavior. Note that some keywords, such as "$schema", apply to the lexical @@ -724,7 +722,8 @@ While custom identifier keywords are possible, vocabulary designers should take care not to disrupt the functioning of core keywords. For example, the "$dyanmicAnchor" keyword in this specification limits its URI resolution - effects to the matching "$dyanmicRef" keyword, leaving "$ref" undisturbed. + effects to the matching "$dyanmicRef" keyword, leaving the behavior + of "$ref" undisturbed.
@@ -775,7 +774,7 @@ For some by-reference applicators, such as "$ref", the referenced schema can be determined by static analysis of the schema document's lexical scope. Others, - such as "$dyanmicRef" and "$dyanmicAnchor", may make use of dynamic + such as "$dyanmicRef" (with "$dyanmicAnchor"), may make use of dynamic scoping, and therefore only be resolvable in the process of evaluating the schema with an instance. @@ -1377,8 +1376,7 @@
-
+
Using JSON Pointer fragments requires knowledge of the structure of the schema. When writing schema documents with the intention to provide re-usable @@ -1387,8 +1385,32 @@ without requiring JSON Pointer references to be updated. - The "$anchor" keyword is used to specify such a fragment. It is an - identifier keyword that can only be used to create plain name fragments. + The "$anchor" and "$dynamicAnchor" keywords are used to specify such + a fragments. They are identifier keywords that can only be used to create + plain name fragments, rather than absolute URIs as seen with "$id". + The behavior of the created fragment is identical for both keywords. + + + The base URI to which the resulting fragment is appended is the canonical + URI of the schema resource containing the "$anchor" or "$dynamicAnchor" + in question. As discussed in the previous section, this is either the + nearest "$id" in the same or parent schema object, or the base URI + for the document as determined according to RFC 3986. + + + Separately from the usual usage of URIs, "$dynamicAnchor" + indicates that the fragment is an extension point when used with + the "$dynamicRef" keyword. This low-level, advanced feature + makes it easier to extend recursive schemas such as the meta-schemas, + without imposing any particular semantics on that extension. + See the section on "$dynamicRef" + for details. + + + In most cases, the normal fragment behavior both sufficies and + is more intuitive. Therefore it is RECOMMENDED that "$anchor" + be used to create plain name fragments unless there is a clear + need for "$dynamicAnchor". If present, the value of this keyword MUST be a string and MUST start with @@ -1403,12 +1425,9 @@ - The base URI to which the resulting fragment is appended is determined - by the "$id" keyword as explained in the previous section. - Two "$anchor" keywords in the same schema document MAY have the same - value if they apply to different base URIs, as the resulting full URIs - will be distinct. However, the effect of two "$anchor" keywords with the - same value and the same base URI is undefined. Implementations MAY + The effect of specifying the same fragment name multiple times within + the same resource, using any combination of "$anchor" and/or + "$dynamicAnchor", is undefined. Implementations MAY raise an error if such usage is detected.
@@ -1417,9 +1436,7 @@ Several keywords can be used to reference a schema which is to be applied to the current instance location. "$ref" and "$dyanmicRef" are applicator - keywords, applying the referenced schema to the instance. "$dyanmicAnchor" - is an identifier keyword that controls how the base URI for resolving - the URI-reference value of "$dyanmicRef is determined. + keywords, applying the referenced schema to the instance. As the values of "$ref" and "$dynamicRef" are URI References, this allows @@ -1447,103 +1464,59 @@ The value of the "$ref" property MUST be a string which is a URI-Reference. Resolved against the current URI base, it produces the URI of the schema - to apply. + to apply. This resolution is safe to perform on schema load, as the + process of evaluating an instance cannot change how the reference resolves.
-
+
+ + The "$dynamicRef" keyword is an applicator that allows for deferring the + full resolution until runtime, at which point it is resolved each time it is + encountered while evaluating an instance. + + + Together with "$dynamicAnchor", "$dynamicRef" implements a cooperative + extension mechanism that is primarily useful with recursive schemas + (schemas that reference themselves). Both the extension point and the + runtime-determined extension target are defined with "$dynamicAnchor", + and only exhibit runtime dynamic behavior when referenced with + "$dynamicRef". + - The "$dyanmicRef" and "$dyanmicAnchor" keywords are used to construct - extensible recursive schemas. A recursive schema is one that has - a reference to its own root, identified by the empty fragment - URI reference ("#"). + The value of the "$dynamicRef" property MUST be a string which is + a URI-Reference. Resolved against the current URI base, it produces + the URI used as the starting point for runtime resolution. This initial + resolution is safe to perform on schema load. - Simply stated, a "$dynamicRef" behaves identically to "$ref", except - when its target schema contains "$dynamicAnchor" with a value of true. - In that case, the dynamic scope is examined to determine a new base URI, - and the URI-reference in "$dynamicRef" is re-evaluated against that - base URI. Unlike base URI changes with "$id", changes with - "$dynamicAnchor" are calculated each time a "$dynamicRef" is - resolved, and do not impact any other keywords. + If the initially resolved starting point URI includes a fragment that + was created by the "$dynamicAnchor" keyword, the initial URI MUST be + replaced by the URI (including the fragment) for the outermost schema + resource in the dynamic scope that defines + an identically named fragment with "$dynamicAnchor". + + Requiring both the initial and final URI fragment to be defined + by "$dynamicAnchor" ensures that the more common "$anchor" + never unexpectedly changes the dynamic resolution process + due to a naming conflict across resources. Users of + "$dynamicAnchor" are expected to be aware of the possibility + of such name collisions, while users of "$anchor" are not. + - For an example using these keyword, see appendix + Otherwise, its behavior is identical to "$ref", and no runtime + resolution is needed. + + + For a full example using theses keyword, see appendix . - The difference between the hyper-schema meta-schema in previous + The difference between the hyper-schema meta-schema in pre-2019 drafts and an this draft dramatically demonstrates the utility of these keywords. -
- - The value of the "$dynamicRef" property MUST be a string which is - a URI-reference. It is a by-reference applicator that uses - a dynamically calculated base URI to resolve its value. - - - The behavior of this keyword is defined only for the value "#". - Implementations MAY choose to consider other values to be errors. - - This restriction may be relaxed in the future, but to date only - the value "#" has a clear use case. - - - - The value of "$dynamicRef" is initially resolved against the - current base URI, in the same manner as for "$ref". - - - The schema identified by the resulting URI is examined for the - presence of "$dynamicAnchor", and a new base URI is calculated - as described for that keyword in the following section. - - - Finally, the value of "$dynamicRef" is resolved against the - new base URI determined according to "$dynamicAnchor" producing - the final resolved reference URI. - - - Note that in the absence of "$dynamicAnchor" (and in some cases - when it is present), "$dynamicRef"'s behavior is identical to - that of "$ref". - - - As with "$ref", the results of this keyword are the results of the - referenced schema. - -
-
- - The value of the "$dynamicAnchor" property MUST be a boolean. - - - "$dynamicAnchor" is used to dynamically identify a base URI - at runtime for "$dynamicRef" by marking where such a calculation - can start, and where it stops. This keyword MUST NOT affect the - base URI of other keywords, unless they are explicitly defined - to rely on it. - - - If set to true, then when the containing schema object is used - as a target of "$dynamicRef", a new base URI is determined - by examining the dynamic scope for - the outermost schema that also contains "$dynamicAnchor" - with a value of true. The base URI of that schema is then used - as the dynamic base URI. - - - If no such schema exists, then the base URI is unchanged. - - - If this keyword is set to false, the base URI is unchanged. - - - Omitting this keyword has the same behavior as a value of false. - -
From d8d7ec0623d628558780d291fd04e020c2200004 Mon Sep 17 00:00:00 2001 From: Henry Andrews Date: Tue, 19 May 2020 23:29:02 -0700 Subject: [PATCH 03/10] Update recursive schema example for $dynamicAnchor This updates for the change of $recursiveRef (with a boolean) to $dynamicAnchor (with a plain name fragment), and provides a more detailed example of how the dynamic scope is used. --- jsonschema-core.xml | 69 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 17 deletions(-) diff --git a/jsonschema-core.xml b/jsonschema-core.xml index 63f56be8..41d925d4 100644 --- a/jsonschema-core.xml +++ b/jsonschema-core.xml @@ -3434,7 +3434,7 @@ https://example.com/schemas/common#/$defs/count/minimum { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "https://example.com/tree", - "$dynamicAnchor": true, + "$dynamicAnchor": "node", "type": "object", "properties": { @@ -3442,7 +3442,7 @@ https://example.com/schemas/common#/$defs/count/minimum "children": { "type": "array", "items": { - "$dynamicRef": "#" + "$dynamicRef": "#node" } } } @@ -3452,7 +3452,7 @@ https://example.com/schemas/common#/$defs/count/minimum { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "https://example.com/strict-tree", - "$dynamicAnchor": true, + "$dynamicAnchor": node, "$ref": "tree", "unevaluatedProperties": false @@ -3465,32 +3465,67 @@ https://example.com/schemas/common#/$defs/count/minimum ]]> + + When we load these two schemas, we will notice the "$dynamicAnchor" + named "node" (note the lack of "#" as this is just the name) + present in each, resulting in the following full schema URIs: + + "https://example.com/tree#node" + "https://example.com/strict-tree#node" + + In addition, JSON Schema implementations keep track of the fact + that these fragments were created with "$dynamicAnchor". + If we apply the "strict-tree" schema to the instance, we will follow the "$ref" to the "tree" schema, examine its "children" subschema, - and find the "$dynamicAnchor" in its "items" subschema. + and find the "$dynamicRef": to "#node" (note the "#" for URI fragment syntax) + in its "items" subschema. That reference resolves to + "https://example.com/tree#node", which is a URI with a fragment + created by "$dynamicAnchor". Therefore we must examine the dynamic + scope before following the reference. + + At this point, the dynamic path is - "#/$ref/properties/children/items/$dynamicRef". + "#/$ref/properties/children/items/$dynamicRef", with a dynamic scope + containing (from the outermost scope to the innermost): + + "https://example.com/strict-tree#" + "https://example.com/tree#" + "https://example.com/tree#/properties/children" + "https://example.com/tree#/properties/children/items" + - The base URI at this point is "https://example.com/tree", so the - "$dynamicRef" initially resolves to "https://example.com/tree#". - Since "$dynamicAnchor" is true, we examine the dynamic path to - see if there is a different base URI to use. We find - "$dynamicAnchor" with a true value at the dynamic paths of - "#" and "#/$ref". + Since we are looking for a plain name fragment, which can be + defined anywhere within a schema resource, the JSON Pointer fragments + are irrelevant to this check. That means that we can remove those + fragments and eliminate consecutive duplicates, producing: + + "https://example.com/strict-tree" + "https://example.com/tree" + - The outermost is "#", which is the root schema of the "strict-tree" - schema, so we use its base URI of "https://example.com/strict-tree", - which produces a final resolved URI of - "https://example.com/strict-tree#" for the "$dynamicRef". + In this case, the outermost resource also has a "node" fragment + defined by "$dynamicAnchor". Therefore instead of resolving the + "$dynamicRef" to "https://example.com/tree#node", we resolve it to + "https://example.com/strict-tree#node". This way, the recursion in the "tree" schema recurses to the root of "strict-tree", instead of only applying "strict-tree" to the instance root, but applying "tree" to instance children. + + This example shows both "$dynamicAnchor"s in the same place + in each schema, specifically the resource root schema. + Since plain-name fragments are independent of the JSON structure, + this would work just as well if one or both of the node schema objects + were moved under "$defs". It is the matching "$dynamicAnchor" values + which tell us how to resolve the dynamic reference, not any sort of + correlation in JSON structure. +
@@ -3590,7 +3625,7 @@ https://example.com/schemas/common#/$defs/count/minimum { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "https://example.com/meta/general-use-example", - "$dynamicAnchor": true, + "$dynamicAnchor": "meta", "$vocabulary": { "https://json-schema.org/draft/2019-09/vocab/core": true, "https://json-schema.org/draft/2019-09/vocab/applicator": true, @@ -3625,7 +3660,7 @@ https://example.com/schemas/common#/$defs/count/minimum { "$schema": "https://json-schema.org/draft/2019-09/schema", "$id": "https://example.com/meta/example-vocab", - "$dynamicAnchor": true, + "$dynamicAnchor": "meta", "$vocabulary": { "https://example.com/vocab/example-vocab": true, }, From 1875b36a7c8c8b67379d3581729f8cbc1ad27b16 Mon Sep 17 00:00:00 2001 From: Henry Andrews Date: Wed, 20 May 2020 14:00:45 -0700 Subject: [PATCH 04/10] Changelog for $recursive* => $dynamic* --- jsonschema-core.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jsonschema-core.xml b/jsonschema-core.xml index 41d925d4..00f8b964 100644 --- a/jsonschema-core.xml +++ b/jsonschema-core.xml @@ -3801,9 +3801,9 @@ https://example.com/schemas/common#/$defs/count/minimum Array-value "items" functionality is now "prefixItems" "items" subsumes the old function of "additionalItems" "contains" and "unevaluatedItems" interactions now specified - - - + Rename $recursive* to $dynamic* + $dynamicAnchor defines a fragment like $anchor + $dynamic* no longer use runtime base URI determination From 46ae0148cde41888626c0858b9761cba51a1fbf6 Mon Sep 17 00:00:00 2001 From: Henry Andrews Date: Wed, 20 May 2020 16:25:23 -0700 Subject: [PATCH 05/10] Update meta-schemas for $dynamic* Replace $recursiveAnchor: true with $dynamicAnchor: "meta" and update $recursiveRef to $dynamicRef accordingly. --- hyper-schema.json | 2 +- links.json | 9 +++++---- meta/applicator.json | 30 +++++++++++++++--------------- meta/content.json | 4 ++-- meta/core.json | 4 ++-- meta/format.json | 2 +- meta/hyper-schema.json | 2 +- meta/meta-data.json | 2 +- meta/validation.json | 2 +- schema.json | 6 +++--- 10 files changed, 32 insertions(+), 31 deletions(-) diff --git a/hyper-schema.json b/hyper-schema.json index 28f9ad4f..484af6c5 100644 --- a/hyper-schema.json +++ b/hyper-schema.json @@ -10,7 +10,7 @@ "https://json-schema.org/draft/2019-09/vocab/content": true, "https://json-schema.org/draft/2019-09/vocab/hyper-schema": true }, - "$recursiveAnchor": true, + "$dynamicAnchor": "meta", "title": "JSON Hyper-Schema", "allOf": [ diff --git a/links.json b/links.json index 7b1a578f..07ad7a42 100644 --- a/links.json +++ b/links.json @@ -2,6 +2,7 @@ "$schema": "https://json-schema.org/draft/2019-09/hyper-schema", "$id": "https://json-schema.org/draft/2019-09/links", "title": "Link Description Object", + "allOf": [ { "required": [ "rel", "href" ] }, { "$ref": "#/$defs/noRequiredFields" } @@ -36,7 +37,7 @@ "format": "uri-template" }, "hrefSchema": { - "$recursiveRef": "https://json-schema.org/draft/2019-09/hyper-schema", + "$dynamicRef": "https://json-schema.org/draft/2019-09/hyper-schema#meta", "default": false }, "templatePointers": { @@ -63,7 +64,7 @@ "type": "string" }, "targetSchema": { - "$recursiveRef": "https://json-schema.org/draft/2019-09/hyper-schema", + "$dynamicRef": "https://json-schema.org/draft/2019-09/hyper-schema#meta", "default": true }, "targetMediaType": { @@ -71,7 +72,7 @@ }, "targetHints": { }, "headerSchema": { - "$recursiveRef": "https://json-schema.org/draft/2019-09/hyper-schema", + "$dynamicRef": "https://json-schema.org/draft/2019-09/hyper-schema#meta", "default": true }, "submissionMediaType": { @@ -79,7 +80,7 @@ "default": "application/json" }, "submissionSchema": { - "$recursiveRef": "https://json-schema.org/draft/2019-09/hyper-schema", + "$dynamicRef": "https://json-schema.org/draft/2019-09/hyper-schema#meta", "default": true }, "$comment": { diff --git a/meta/applicator.json b/meta/applicator.json index 50052914..6b4ac989 100644 --- a/meta/applicator.json +++ b/meta/applicator.json @@ -4,47 +4,47 @@ "$vocabulary": { "https://json-schema.org/draft/2019-09/vocab/applicator": true }, - "$recursiveAnchor": true, + "$dynamicAnchor": "meta", "title": "Applicator vocabulary meta-schema", "properties": { "prefixItems": { "$ref": "#/$defs/schemaArray" }, - "items": { "$recursiveRef": "#" }, - "unevaluatedItems": { "$recursiveRef": "#" }, - "contains": { "$recursiveRef": "#" }, - "additionalProperties": { "$recursiveRef": "#" }, - "unevaluatedProperties": { "$recursiveRef": "#" }, + "items": { "$dynamicRef": "#meta" }, + "unevaluatedItems": { "$dynamicRef": "#meta" }, + "contains": { "$dynamicRef": "#meta" }, + "additionalProperties": { "$dynamicRef": "#meta" }, + "unevaluatedProperties": { "$dynamicRef": "#meta" }, "properties": { "type": "object", - "additionalProperties": { "$recursiveRef": "#" }, + "additionalProperties": { "$dynamicRef": "#meta" }, "default": {} }, "patternProperties": { "type": "object", - "additionalProperties": { "$recursiveRef": "#" }, + "additionalProperties": { "$dynamicRef": "#meta" }, "propertyNames": { "format": "regex" }, "default": {} }, "dependentSchemas": { "type": "object", "additionalProperties": { - "$recursiveRef": "#" + "$dynamicRef": "#meta" } }, - "propertyNames": { "$recursiveRef": "#" }, - "if": { "$recursiveRef": "#" }, - "then": { "$recursiveRef": "#" }, - "else": { "$recursiveRef": "#" }, + "propertyNames": { "$dynamicRef": "#meta" }, + "if": { "$dynamicRef": "#meta" }, + "then": { "$dynamicRef": "#meta" }, + "else": { "$dynamicRef": "#meta" }, "allOf": { "$ref": "#/$defs/schemaArray" }, "anyOf": { "$ref": "#/$defs/schemaArray" }, "oneOf": { "$ref": "#/$defs/schemaArray" }, - "not": { "$recursiveRef": "#" } + "not": { "$dynamicRef": "#meta" } }, "$defs": { "schemaArray": { "type": "array", "minItems": 1, - "items": { "$recursiveRef": "#" } + "items": { "$dynamicRef": "#meta" } } } } diff --git a/meta/content.json b/meta/content.json index f6752a8e..e69ccdfa 100644 --- a/meta/content.json +++ b/meta/content.json @@ -4,7 +4,7 @@ "$vocabulary": { "https://json-schema.org/draft/2019-09/vocab/content": true }, - "$recursiveAnchor": true, + "$dynamicAnchor": "meta", "title": "Content vocabulary meta-schema", @@ -12,6 +12,6 @@ "properties": { "contentMediaType": { "type": "string" }, "contentEncoding": { "type": "string" }, - "contentSchema": { "$recursiveRef": "#" } + "contentSchema": { "$dynamicRef": "#meta" } } } diff --git a/meta/core.json b/meta/core.json index 3d5311bf..3a84feb1 100644 --- a/meta/core.json +++ b/meta/core.json @@ -4,7 +4,7 @@ "$vocabulary": { "https://json-schema.org/draft/2019-09/vocab/core": true }, - "$recursiveAnchor": true, + "$dynamicAnchor": "meta", "title": "Core vocabulary meta-schema", "type": ["object", "boolean"], @@ -51,7 +51,7 @@ }, "$defs": { "type": "object", - "additionalProperties": { "$recursiveRef": "#" }, + "additionalProperties": { "$dynamicRef": "#meta" }, "default": {} } } diff --git a/meta/format.json b/meta/format.json index 09bbfdda..68ad5b0d 100644 --- a/meta/format.json +++ b/meta/format.json @@ -4,7 +4,7 @@ "$vocabulary": { "https://json-schema.org/draft/2019-09/vocab/format": true }, - "$recursiveAnchor": true, + "$dynamicAnchor": "meta", "title": "Format vocabulary meta-schema", "type": ["object", "boolean"], diff --git a/meta/hyper-schema.json b/meta/hyper-schema.json index 3d230589..f36d3477 100644 --- a/meta/hyper-schema.json +++ b/meta/hyper-schema.json @@ -4,7 +4,7 @@ "$vocabulary": { "https://json-schema.org/draft/2019-09/vocab/hyper-schema": true }, - "$recursiveAnchor": true, + "$dynamicAnchor": "meta", "title": "JSON Hyper-Schema Vocabulary Schema", "type": ["object", "boolean"], diff --git a/meta/meta-data.json b/meta/meta-data.json index da04cff6..bbb171e9 100644 --- a/meta/meta-data.json +++ b/meta/meta-data.json @@ -4,7 +4,7 @@ "$vocabulary": { "https://json-schema.org/draft/2019-09/vocab/meta-data": true }, - "$recursiveAnchor": true, + "$dynamicAnchor": "meta", "title": "Meta-data vocabulary meta-schema", diff --git a/meta/validation.json b/meta/validation.json index 9f59677b..75ba4522 100644 --- a/meta/validation.json +++ b/meta/validation.json @@ -4,7 +4,7 @@ "$vocabulary": { "https://json-schema.org/draft/2019-09/vocab/validation": true }, - "$recursiveAnchor": true, + "$dynamicAnchor": "meta", "title": "Validation vocabulary meta-schema", "type": ["object", "boolean"], diff --git a/schema.json b/schema.json index 2248a0c8..4d4e8782 100644 --- a/schema.json +++ b/schema.json @@ -9,7 +9,7 @@ "https://json-schema.org/draft/2019-09/vocab/format": false, "https://json-schema.org/draft/2019-09/vocab/content": true }, - "$recursiveAnchor": true, + "$dynamicAnchor": "meta", "title": "Core and Validation specifications meta-schema", "allOf": [ @@ -25,7 +25,7 @@ "definitions": { "$comment": "While no longer an official keyword as it is replaced by $defs, this keyword is retained in the meta-schema to prevent incompatible extensions as it remains in common use.", "type": "object", - "additionalProperties": { "$recursiveRef": "#" }, + "additionalProperties": { "$dynamicRef": "#meta" }, "default": {} }, "dependencies": { @@ -33,7 +33,7 @@ "type": "object", "additionalProperties": { "anyOf": [ - { "$recursiveRef": "#" }, + { "$dynamicRef": "#meta" }, { "$ref": "meta/validation#/$defs/stringArray" } ] } From 30f97c815ad8c697546da3273cde9dcab3ea2e65 Mon Sep 17 00:00:00 2001 From: Henry Andrews Date: Wed, 27 May 2020 23:53:21 -0700 Subject: [PATCH 06/10] Fix typo --- jsonschema-core.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsonschema-core.xml b/jsonschema-core.xml index 00f8b964..abf0d6c0 100644 --- a/jsonschema-core.xml +++ b/jsonschema-core.xml @@ -1386,7 +1386,7 @@ The "$anchor" and "$dynamicAnchor" keywords are used to specify such - a fragments. They are identifier keywords that can only be used to create + fragments. They are identifier keywords that can only be used to create plain name fragments, rather than absolute URIs as seen with "$id". The behavior of the created fragment is identical for both keywords. From 219cbc34e8126e7d396658788697a7ee24f6c412 Mon Sep 17 00:00:00 2001 From: Ben Hutton Date: Thu, 25 Jun 2020 20:54:17 +0100 Subject: [PATCH 07/10] Fix typo /dyanmic/dynamic/ --- jsonschema-core.xml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/jsonschema-core.xml b/jsonschema-core.xml index abf0d6c0..3df35f9a 100644 --- a/jsonschema-core.xml +++ b/jsonschema-core.xml @@ -624,7 +624,7 @@ which must be resolved against another value, such as another URI-reference or a full URI, which is found through the lexical structure of the JSON document. The "$id", "$ref", and - "$dyanmicRef" core keywords, and the "base" JSON Hyper-Schema + "$dynamicRef" core keywords, and the "base" JSON Hyper-Schema keyword, are examples of this sort of behavior. @@ -638,12 +638,12 @@ with an instance document. The outermost dynamic scope is the root schema of the schema document in which processing begins. The path from this root schema to any particular keyword (that - includes any "$ref" and "$dyanmicRef" keywords that may have + includes any "$ref" and "$dynamicRef" keywords that may have been resolved) is considered the keyword's "validation path." Or should this be the schema object at which processing begins, even if it is not a root? This has some implications - for the case where "$dyanmicAnchor" is only allowed in the + for the case where "$dynamicAnchor" is only allowed in the root schema but processing begins in a subschema. @@ -658,8 +658,8 @@ dynamic parent, rather than examining the local lexically enclosing parent. - The concept of dynamic scope is primarily used with "$dyanmicRef" and - "$dyanmicAnchor", and should be considered an advanced feature + The concept of dynamic scope is primarily used with "$dynamicRef" and + "$dynamicAnchor", and should be considered an advanced feature and used with caution when defining additional keywords. It also appears when reporting errors and collected annotations, as it may be possible to revisit the same lexical scope repeatedly with different dynamic @@ -721,8 +721,8 @@ While custom identifier keywords are possible, vocabulary designers should take care not to disrupt the functioning of core keywords. For example, - the "$dyanmicAnchor" keyword in this specification limits its URI resolution - effects to the matching "$dyanmicRef" keyword, leaving the behavior + the "$dynamicAnchor" keyword in this specification limits its URI resolution + effects to the matching "$dynamicRef" keyword, leaving the behavior of "$ref" undisturbed.
@@ -774,7 +774,7 @@ For some by-reference applicators, such as "$ref", the referenced schema can be determined by static analysis of the schema document's lexical scope. Others, - such as "$dyanmicRef" (with "$dyanmicAnchor"), may make use of dynamic + such as "$dynamicRef" (with "$dynamicAnchor"), may make use of dynamic scoping, and therefore only be resolvable in the process of evaluating the schema with an instance. @@ -1435,7 +1435,7 @@
Several keywords can be used to reference a schema which is to be applied to the - current instance location. "$ref" and "$dyanmicRef" are applicator + current instance location. "$ref" and "$dynamicRef" are applicator keywords, applying the referenced schema to the instance. From 2dcb418738b741bab8fd81c561d7aa16d37231e3 Mon Sep 17 00:00:00 2001 From: Ben Hutton Date: Thu, 25 Jun 2020 21:09:44 +0100 Subject: [PATCH 08/10] Fixed typo /theses/these/ --- jsonschema-core.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsonschema-core.xml b/jsonschema-core.xml index 3df35f9a..effc6f83 100644 --- a/jsonschema-core.xml +++ b/jsonschema-core.xml @@ -1509,7 +1509,7 @@ resolution is needed. - For a full example using theses keyword, see appendix + For a full example using these keyword, see appendix . The difference between the hyper-schema meta-schema in pre-2019 From 8e5f8e17f76835f5dde331478450ce6fdcbceef9 Mon Sep 17 00:00:00 2001 From: Ben Hutton Date: Fri, 3 Jul 2020 20:49:37 +0100 Subject: [PATCH 09/10] Fix typo --- jsonschema-core.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsonschema-core.xml b/jsonschema-core.xml index effc6f83..6cc96c22 100644 --- a/jsonschema-core.xml +++ b/jsonschema-core.xml @@ -1407,7 +1407,7 @@ for details. - In most cases, the normal fragment behavior both sufficies and + In most cases, the normal fragment behavior both suffices and is more intuitive. Therefore it is RECOMMENDED that "$anchor" be used to create plain name fragments unless there is a clear need for "$dynamicAnchor". From 98210634a57f1d0c22b79a316878ecbcb06c63af Mon Sep 17 00:00:00 2001 From: Ben Hutton Date: Fri, 3 Jul 2020 21:00:58 +0100 Subject: [PATCH 10/10] Clarify changelog item regarding $dynamic* --- jsonschema-core.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsonschema-core.xml b/jsonschema-core.xml index 6cc96c22..6471c543 100644 --- a/jsonschema-core.xml +++ b/jsonschema-core.xml @@ -3803,7 +3803,7 @@ https://example.com/schemas/common#/$defs/count/minimum "contains" and "unevaluatedItems" interactions now specified Rename $recursive* to $dynamic* $dynamicAnchor defines a fragment like $anchor - $dynamic* no longer use runtime base URI determination + $dynamic* (previously $recursive) no longer use runtime base URI determination