From 68db6f3b359dedde499dec75523c16a5a652adea Mon Sep 17 00:00:00 2001 From: Henry Andrews Date: Wed, 23 May 2018 23:18:05 -0700 Subject: [PATCH 1/7] Add "$recurse" for extending recursive schemas --- jsonschema-core.xml | 85 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 83 insertions(+), 2 deletions(-) diff --git a/jsonschema-core.xml b/jsonschema-core.xml index 557f2747..286ffb75 100644 --- a/jsonschema-core.xml +++ b/jsonschema-core.xml @@ -571,9 +571,10 @@ Authors of extensions to JSON Schema are encouraged to write their own - meta-schemas, which extend the existing meta-schemas using "allOf". + meta-schemas, which MAY extend the existing meta-schemas using "allOf". This extended meta-schema SHOULD be referenced using the "$schema" keyword, to - allow tools to follow the correct behaviour. + allow tools to follow the correct behaviour. The "$recurse" keyword is + provided to facilitate this usage. Note that the recursive nature of meta-schemas requires re-defining @@ -904,6 +905,86 @@ +
+ + This keyword's value MUST be the boolean literal true. + + Future drafts may extend the usage with other values. The immediate + use case does not require any targets other than the entry point + root, and a regular fragment URI reference does not provide the + correct semantics. Should other values be added in the future, + it is expected that a boolean true value will remain an alias for + this original use case. + + + + The presence of this keyword with a boolean true value indicates that, + during processing, it MUST be treated as a reference to the schema document + where processing was initiated. + + + This document, known as the entry point schema, is the schema document that + was initially supplied to the implementation, as opposed to schema documents + that were processed as a result of following a "$ref" reference. Note that + even if processing began at a subschema within a document, the "$recurse" + target MUST be the root of the document. + + + Aside from the dynamic definition of the reference target, a "$recurse" + reference MUST behave identically to a "$ref" reference. + +
+ + Given the following schemas: + + + + +
+ + When an implementation begins processing with the + "https://example.com/base" schema, both the "local" and "recursive" + references resolve to "https://example.com/base". The entry point + schema and the schema being processed are the same. + + + However, when an implementation begins processing with the + "https://example.com/extension" schema, and processes the + "https://example.com/base" schema as a result of following the "$ref" + within the "extended" property, now the entry point schema is + "https://example.com/extension". + + + Therefore the "local" property's reference + still resolves to "https://example.com/base" while the "recursive" property's + reference now resolves to "https://example.com/extension". + This behavior remains the same even if the implementation begins processing + at "https://example.com/extension#/properties/extended". + +
+
The "$defs" keyword provides a standardized location for schema From e9faf6e14572486e4b92f5db6f6cc5b54fb7f71c Mon Sep 17 00:00:00 2001 From: Henry Andrews Date: Wed, 23 May 2018 23:18:29 -0700 Subject: [PATCH 2/7] Add "$recurse" to the meta-schemas This allows deleting most of the hyper-schema meta-schema. --- hyper-schema.json | 49 ----------------------------------------------- schema.json | 34 +++++++++++++++++--------------- 2 files changed, 19 insertions(+), 64 deletions(-) diff --git a/hyper-schema.json b/hyper-schema.json index 82cf32fa..fc51b1bc 100644 --- a/hyper-schema.json +++ b/hyper-schema.json @@ -2,57 +2,8 @@ "$schema": "http://json-schema.org/draft-08/hyper-schema#", "$id": "http://json-schema.org/draft-08/hyper-schema#", "title": "JSON Hyper-Schema", - "$defs": { - "schemaArray": { - "allOf": [ - { "$ref": "http://json-schema.org/draft-08/schema#/$defs/schemaArray" }, - { - "items": { "$ref": "#" } - } - ] - } - }, "allOf": [ { "$ref": "http://json-schema.org/draft-08/schema#" } ], "properties": { - "additionalItems": { "$ref": "#" }, - "additionalProperties": { "$ref": "#"}, - "dependencies": { - "additionalProperties": { - "anyOf": [ - { "$ref": "#" }, - { "type": "array" } - ] - } - }, - "items": { - "anyOf": [ - { "$ref": "#" }, - { "$ref": "#/$defs/schemaArray" } - ] - }, - "$defs": { - "additionalProperties": { "$ref": "#" } - }, - "definitions": { - "$comment": "Renamed to $defs, but retained here to ensure compatibility", - "additionalProperties": { "$ref": "#" } - }, - "patternProperties": { - "additionalProperties": { "$ref": "#" } - }, - "properties": { - "additionalProperties": { "$ref": "#" } - }, - "if": {"$ref": "#"}, - "then": {"$ref": "#"}, - "else": {"$ref": "#"}, - "allOf": { "$ref": "#/$defs/schemaArray" }, - "anyOf": { "$ref": "#/$defs/schemaArray" }, - "oneOf": { "$ref": "#/$defs/schemaArray" }, - "not": { "$ref": "#" }, - "contains": { "$ref": "#" }, - "propertyNames": { "$ref": "#" }, - "base": { "type": "string", "format": "uri-template" diff --git a/schema.json b/schema.json index 182eefb0..1442d1b2 100644 --- a/schema.json +++ b/schema.json @@ -6,7 +6,7 @@ "schemaArray": { "type": "array", "minItems": 1, - "items": { "$ref": "#" } + "items": { "$recurse": true } }, "nonNegativeInteger": { "type": "integer", @@ -50,18 +50,22 @@ "type": "string", "format": "uri-reference" }, + "$recurse": { + "type": "boolean", + "const": true + }, "$comment": { "type": "string" }, "$defs": { "type": "object", - "additionalProperties": { "$ref": "#" }, + "additionalProperties": { "$recurse": true }, "default": {} }, "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": { "$ref": "#" }, + "additionalProperties": { "$recurse": true }, "default": {} }, "title": { @@ -101,10 +105,10 @@ "type": "string", "format": "regex" }, - "additionalItems": { "$ref": "#" }, + "additionalItems": { "$recurse": true }, "items": { "anyOf": [ - { "$ref": "#" }, + { "$recurse": true }, { "$ref": "#/$defs/schemaArray" } ], "default": true @@ -115,19 +119,19 @@ "type": "boolean", "default": false }, - "contains": { "$ref": "#" }, + "contains": { "$recurse": true }, "maxProperties": { "$ref": "#/$defs/nonNegativeInteger" }, "minProperties": { "$ref": "#/$defs/nonNegativeIntegerDefault0" }, "required": { "$ref": "#/$defs/stringArray" }, - "additionalProperties": { "$ref": "#" }, + "additionalProperties": { "$recurse": true }, "properties": { "type": "object", - "additionalProperties": { "$ref": "#" }, + "additionalProperties": { "$recurse": true }, "default": {} }, "patternProperties": { "type": "object", - "additionalProperties": { "$ref": "#" }, + "additionalProperties": { "$recurse": true }, "propertyNames": { "format": "regex" }, "default": {} }, @@ -135,12 +139,12 @@ "type": "object", "additionalProperties": { "anyOf": [ - { "$ref": "#" }, + { "$recurse": true }, { "$ref": "#/$defs/stringArray" } ] } }, - "propertyNames": { "$ref": "#" }, + "propertyNames": { "$recurse": true }, "const": true, "enum": { "type": "array", @@ -162,13 +166,13 @@ "format": { "type": "string" }, "contentMediaType": { "type": "string" }, "contentEncoding": { "type": "string" }, - "if": {"$ref": "#"}, - "then": {"$ref": "#"}, - "else": {"$ref": "#"}, + "if": {"$recurse": true}, + "then": {"$recurse": true}, + "else": {"$recurse": true}, "allOf": { "$ref": "#/$defs/schemaArray" }, "anyOf": { "$ref": "#/$defs/schemaArray" }, "oneOf": { "$ref": "#/$defs/schemaArray" }, - "not": { "$ref": "#" } + "not": { "$recurse": true } }, "default": true } From ba1a4989c09f5b99148b03c33192db771d6b2623 Mon Sep 17 00:00:00 2001 From: Henry Andrews Date: Thu, 24 May 2018 15:31:57 -0700 Subject: [PATCH 3/7] Add xref for schema document, fix $schema Feedback from PR review. --- jsonschema-core.xml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/jsonschema-core.xml b/jsonschema-core.xml index 286ffb75..21497727 100644 --- a/jsonschema-core.xml +++ b/jsonschema-core.xml @@ -363,7 +363,7 @@
-
+
A JSON Schema document, or simply a schema, is a JSON document used to describe an instance. @@ -919,8 +919,9 @@ The presence of this keyword with a boolean true value indicates that, - during processing, it MUST be treated as a reference to the schema document - where processing was initiated. + during processing, it MUST be treated as a reference to the + schema document where processing + was initiated. This document, known as the entry point schema, is the schema document that @@ -940,6 +941,7 @@ Date: Thu, 24 May 2018 22:22:18 -0700 Subject: [PATCH 4/7] Add "$recurse" to changelog --- jsonschema-core.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/jsonschema-core.xml b/jsonschema-core.xml index 21497727..45225a96 100644 --- a/jsonschema-core.xml +++ b/jsonschema-core.xml @@ -1727,6 +1727,7 @@ User-Agent: product-name/5.4.1 so-cool-json-schema/1.0.2 curl/7.43.0 Moved "definitions" from the Validation specification here as "$defs" Moved applicator keywords from the Validation specification as their own vocabulary Moved "dependencies" from the Validation specification, but only the schema form + Added "$recurse" for dynamically evaluated recursive references From da7bdf423284dbea8c1fe24f8c3d9911e1bf284f Mon Sep 17 00:00:00 2001 From: Henry Andrews Date: Thu, 24 May 2018 15:44:11 -0700 Subject: [PATCH 5/7] Consolidate sections on reference keywords. This commit *only* includes formatting changes: * New overall section title * New section title for the now sub-section on "$ref" * "$ref" subsection indented and wrapped to 100 characters * "$recurse" section moved to right after "$ref" sub-section * "$recurse subsection indented and wrapped to 100 characters * Other reference subsections wrapped to 100 characters as needed The next commit will update the actual text. --- jsonschema-core.xml | 231 ++++++++++++++++++++++---------------------- 1 file changed, 117 insertions(+), 114 deletions(-) diff --git a/jsonschema-core.xml b/jsonschema-core.xml index 45225a96..403406ee 100644 --- a/jsonschema-core.xml +++ b/jsonschema-core.xml @@ -791,40 +791,125 @@
- - The "$ref" keyword is used to reference a schema, and provides the ability to - validate recursive structures through self-reference. - - - An object schema with a "$ref" property MUST be interpreted as a "$ref" reference. - The value of the "$ref" property MUST be a URI Reference. - Resolved against the current URI base, it identifies the URI of a schema to use. - All other properties in a "$ref" object MUST be ignored. - - - The URI is not a network locator, only an identifier. A schema need not be - downloadable from the address if it is a network-addressable URL, and - implementations SHOULD NOT assume they should perform a network operation when they - encounter a network-addressable URI. - - - A schema MUST NOT be run into an infinite loop against a schema. For example, if two - schemas "#alice" and "#bob" both have an "allOf" property that refers to the other, - a naive validator might get stuck in an infinite recursive loop trying to validate - the instance. - Schemas SHOULD NOT make use of infinite recursive nesting like this; the behavior is - undefined. - +
+ + The "$ref" keyword is used to reference a schema, and provides the ability + to validate recursive structures through self-reference. + + + An object schema with a "$ref" property MUST be interpreted as a "$ref" + reference. The value of the "$ref" property MUST be a URI Reference. + Resolved against the current URI base, it identifies the URI of a schema + to use. All other properties in a "$ref" object MUST be ignored. + + + The URI is not a network locator, only an identifier. A schema need not be + downloadable from the address if it is a network-addressable URL, and + implementations SHOULD NOT assume they should perform a network operation + when they encounter a network-addressable URI. + + + A schema MUST NOT be run into an infinite loop against a schema. For + example, if two schemas "#alice" and "#bob" both have an "allOf" property + that refers to the other, a naive validator might get stuck in an infinite + recursive loop trying to validate the instance. Schemas SHOULD NOT make + use of infinite recursive nesting like this; the behavior is undefined. + +
+ +
+ + This keyword's value MUST be the boolean literal true. + + Future drafts may extend the usage with other values. The immediate + use case does not require any targets other than the entry point + root, and a regular fragment URI reference does not provide the + correct semantics. Should other values be added in the future, + it is expected that a boolean true value will remain an alias for + this original use case. + + + + The presence of this keyword with a boolean true value indicates that, + during processing, it MUST be treated as a reference to the + schema document where processing + was initiated. + + + This document, known as the entry point schema, is the schema document that + was initially supplied to the implementation, as opposed to schema documents + that were processed as a result of following a "$ref" reference. Note that + even if processing began at a subschema within a document, the "$recurse" + target MUST be the root of the document. + + + Aside from the dynamic definition of the reference target, a "$recurse" + reference MUST behave identically to a "$ref" reference. + +
+ + Given the following schemas: + + + + +
+ + When an implementation begins processing with the + "https://example.com/base" schema, both the "local" and "recursive" + references resolve to "https://example.com/base". The entry point + schema and the schema being processed are the same. + + + However, when an implementation begins processing with the + "https://example.com/extension" schema, and processes the + "https://example.com/base" schema as a result of following the "$ref" + within the "extended" property, now the entry point schema is + "https://example.com/extension". + + + Therefore the "local" property's reference + still resolves to "https://example.com/base" while the "recursive" + property's reference now resolves to "https://example.com/extension". + This behavior remains the same even if the implementation begins processing + at "https://example.com/extension#/properties/extended". + +
+
- The use of URIs to identify remote schemas does not necessarily mean anything is downloaded, - but instead JSON Schema implementations SHOULD understand ahead of time which schemas they will be using, - and the URIs that identify them. + The use of URIs to identify remote schemas does not necessarily mean + anything is downloaded, but instead JSON Schema implementations SHOULD + understand ahead of time which schemas they will be using, and the URIs + that identify them. - When schemas are downloaded, - for example by a generic user-agent that doesn't know until runtime which schemas to download, - see Usage for Hypermedia. + When schemas are downloaded, for example by a generic user-agent that + doesn't know until runtime which schemas to download, see + Usage for Hypermedia. Implementations SHOULD be able to associate arbitrary URIs with an arbitrary @@ -850,8 +935,8 @@ If the resulting URI identifies a schema within the current document, or - within another schema document that has been made available to the implementation, - then that schema SHOULD be used automatically. + within another schema document that has been made available to the + implementation, then that schema SHOULD be used automatically. For example, consider this schema: @@ -905,88 +990,6 @@
-
- - This keyword's value MUST be the boolean literal true. - - Future drafts may extend the usage with other values. The immediate - use case does not require any targets other than the entry point - root, and a regular fragment URI reference does not provide the - correct semantics. Should other values be added in the future, - it is expected that a boolean true value will remain an alias for - this original use case. - - - - The presence of this keyword with a boolean true value indicates that, - during processing, it MUST be treated as a reference to the - schema document where processing - was initiated. - - - This document, known as the entry point schema, is the schema document that - was initially supplied to the implementation, as opposed to schema documents - that were processed as a result of following a "$ref" reference. Note that - even if processing began at a subschema within a document, the "$recurse" - target MUST be the root of the document. - - - Aside from the dynamic definition of the reference target, a "$recurse" - reference MUST behave identically to a "$ref" reference. - -
- - Given the following schemas: - - - - -
- - When an implementation begins processing with the - "https://example.com/base" schema, both the "local" and "recursive" - references resolve to "https://example.com/base". The entry point - schema and the schema being processed are the same. - - - However, when an implementation begins processing with the - "https://example.com/extension" schema, and processes the - "https://example.com/base" schema as a result of following the "$ref" - within the "extended" property, now the entry point schema is - "https://example.com/extension". - - - Therefore the "local" property's reference - still resolves to "https://example.com/base" while the "recursive" property's - reference now resolves to "https://example.com/extension". - This behavior remains the same even if the implementation begins processing - at "https://example.com/extension#/properties/extended". - -
-
The "$defs" keyword provides a standardized location for schema From d15f13f3e5e26b4097d8fd1794a40878c1fe9f4a Mon Sep 17 00:00:00 2001 From: Henry Andrews Date: Thu, 24 May 2018 15:53:43 -0700 Subject: [PATCH 6/7] Rework reference sections for new organization Add an intro paragraph about reference keywords and their nature as indirect in-place applicators. "$ref" is no longer really targeted at recursive schemas, so tweak its wording slightly. Do a few further improvements to "$recurse" wording, particularly around root schemas and schema documents. Correct an apparent typo about a schema "against a schema", this is almost certainly supposed to be "against an instance", as the rest of the paragraph talks in terms of instance validation. --- jsonschema-core.xml | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/jsonschema-core.xml b/jsonschema-core.xml index 403406ee..e2a71c5f 100644 --- a/jsonschema-core.xml +++ b/jsonschema-core.xml @@ -790,11 +790,19 @@
-
+
+ + Two keywords are provided for referencing one schema from another, and + for validating recursive structures through self-reference. + Both of these keywords behave as + in-place applicators, except that the schema + being applied is identified rather than appearing as all or part of the + keyword's value. + +
- The "$ref" keyword is used to reference a schema, and provides the ability - to validate recursive structures through self-reference. + The "$ref" keyword is used to reference a statically identified schema. An object schema with a "$ref" property MUST be interpreted as a "$ref" @@ -809,7 +817,7 @@ when they encounter a network-addressable URI. - A schema MUST NOT be run into an infinite loop against a schema. For + A schema MUST NOT be run into an infinite loop against an instance. For example, if two schemas "#alice" and "#bob" both have an "allOf" property that refers to the other, a naive validator might get stuck in an infinite recursive loop trying to validate the instance. Schemas SHOULD NOT make @@ -817,7 +825,10 @@
-
+
+ + The "$recurse" keyword is used to construct extensible recursive schemas. + This keyword's value MUST be the boolean literal true. @@ -831,16 +842,16 @@ The presence of this keyword with a boolean true value indicates that, - during processing, it MUST be treated as a reference to the + during processing, it MUST be treated as a reference to the root of the schema document where processing - was initiated. + was initiated. The current base URI is not relevant to "$recurse". This document, known as the entry point schema, is the schema document that was initially supplied to the implementation, as opposed to schema documents that were processed as a result of following a "$ref" reference. Note that even if processing began at a subschema within a document, the "$recurse" - target MUST be the root of the document. + target MUST be the root schema. Aside from the dynamic definition of the reference target, a "$recurse" @@ -1092,7 +1103,8 @@
-
+
These keywords apply subschemas to the same location in the instance as the parent schema is being applied. They allow combining From 46252c8c738a7597a2c1f4a8f3ccd32b1c853295 Mon Sep 17 00:00:00 2001 From: Henry Andrews Date: Fri, 25 May 2018 18:54:26 -0700 Subject: [PATCH 7/7] Meta-schema extension is no longer hard So remove the advice about that part. --- jsonschema-core.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/jsonschema-core.xml b/jsonschema-core.xml index e2a71c5f..1ad6b6d7 100644 --- a/jsonschema-core.xml +++ b/jsonschema-core.xml @@ -576,11 +576,6 @@ allow tools to follow the correct behaviour. The "$recurse" keyword is provided to facilitate this usage. - - Note that the recursive nature of meta-schemas requires re-defining - recursive keywords in the extended meta-schema, as can be seen in - the JSON Hyper-Schema meta-schema. -