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/jsonschema-core.xml b/jsonschema-core.xml
index 557f2747..1ad6b6d7 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.
@@ -571,14 +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.
-
-
- 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.
+ allow tools to follow the correct behaviour. The "$recurse" keyword is
+ provided to facilitate this usage.
@@ -789,41 +785,137 @@
-
-
- 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.
+ 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 statically identified schema.
+
+
+ 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 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
+ use of infinite recursive nesting like this; the behavior is undefined.
+
+
+
+
+
+ The "$recurse" keyword is used to construct extensible recursive schemas.
+
+
+ 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 root of the
+ schema document where processing
+ 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 schema.
+
+
+ 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
@@ -849,8 +941,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:
@@ -1006,7 +1098,8 @@
-
+
These keywords apply subschemas to the same location in the instance
as the parent schema is being applied. They allow combining
@@ -1644,6 +1737,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 vocabularyMoved "dependencies" from the Validation specification, but only the schema form
+ Added "$recurse" for dynamically evaluated recursive references
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
}