Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unevaluated* updates (and some annotation dependency cleanup) #1541

Merged
merged 10 commits into from
Nov 7, 2024
182 changes: 82 additions & 100 deletions jsonschema-core.md
Original file line number Diff line number Diff line change
Expand Up @@ -1645,27 +1645,23 @@ and the instance value are affected by this keyword.
This keyword produces an annotation value which is the largest index to which
this keyword applied a subschema. The value MAY be a boolean true if a subschema
was applied to every index of the instance, such as is produced by the `items`
keyword. This annotation affects the behavior of `items` and `unevaluatedItems`.
keyword.

The presence of this keyword affects the behaviors of [`items`](#items) and
[`unevaluatedItems`](#unevaluateditems).

##### `items` {#items}

The value of `items` MUST be a valid JSON Schema.

This keyword applies its subschema to all instance elements at indexes greater
than the length of the `prefixItems` array in the same schema object, as
reported by the annotation result of that `prefixItems` keyword. If no such
annotation result exists, `items` applies its subschema to all instance array
elements.[^11]

[^11]: Note that the behavior of `items` without `prefixItems` is identical to
that of the schema form of `items` in prior drafts. When `prefixItems` is
present, the behavior of `items` is identical to the former `additionalItems`
keyword.
This keyword applies its subschema to all instance elements at indices greater
than the length of the `prefixItems` array in the same schema object. If
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This keyword applies its subschema to all instance elements at indices greater
than the length of the `prefixItems` array in the same schema object. If
This keyword applies its subschema to all instance elements at indices greater
than or equal to the length of the `prefixItems` array in the same schema object. If

Given that json arrays are indexed from 0: If prefixItems had 3 items, then the items keyword applies to all elements at index 3 and greater, not those greater than 3.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

json arrays are indexed from 0

JSON 8259 doesn't specify and indexing base. Seems more like a programming language thing to me.

I'll see if I can fix this so that it doesn't mention indices at all.

Copy link

@mwadams mwadams Oct 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe

This keyword ignores instance elements in the array, up to and including the number of items found in the prefixItems array in the same schema object. It then applies its subschema to all subsequent instance elements.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://www.rfc-editor.org/rfc/rfc6901.html#section-4 specifies that JSON pointer indexes are zero-based.

I don't see how we can avoid indexes because that's a necessary part of the annotation content for these keywords (and contains contains a list of indexes, not just the number of evaluated/validated elements), and we also use array indexes in any JSON pointer in a $ref, and in keywordLocations and absoluteKeywordLocations in error objects.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a very good point. I think it's important to state that we're using zero-based indexing and reference that section.

I'll work that in. Thanks for the... pointer 😏

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've left this in as-is (without references to indexing), but I've also added a section specifically about array indices.

`prefixItems` does not exist within the same schema object, `items` applies its
subschema to all instance array elements.

If the `items` subschema is applied to any positions within the instance array,
it produces an annotation result of boolean true, indicating that all remaining
array elements have been evaluated against this keyword's subschema. This
annotation affects the behavior of `unevaluatedItems`.
array elements have been evaluated against this keyword's subschema.

Omitting this keyword has the same assertion behavior as an empty schema.

Expand All @@ -1674,6 +1670,9 @@ that produces the same effect, such as by directly checking for the presence and
size of a `prefixItems` array. Implementations that do not support annotation
collection MUST do so.

The presence of this keyword affects the behavior of
[`unevaluatedItems`](#unevaluateditems).

#### Keywords for Applying Subschemas to Objects

##### `properties`
Expand All @@ -1685,11 +1684,13 @@ Validation succeeds if, for each name that appears in both the instance and as a
name within this keyword's value, the child instance for that name successfully
validates against the corresponding schema.

Omitting this keyword has the same assertion behavior as an empty object.

The annotation result of this keyword is the set of instance property names
which are also present under this keyword. This annotation affects the behavior
of `additionalProperties` and `unevaluatedProperties`.
which are also present under this keyword.

Omitting this keyword has the same assertion behavior as an empty object.
The presence of this keyword affects the behaviors of
[`additionalProperties`(#additionalProperties) and [`unevaluatedProperties`](#unevaluatedproperties).

##### `patternProperties`

Expand All @@ -1704,45 +1705,33 @@ instance for that name successfully validates against each schema that
corresponds to a matching regular expression. Recall: regular expressions are
not implicitly anchored.

Omitting this keyword has the same assertion behavior as an empty object.

The annotation result of this keyword is the set of instance property names
matched by at least one property under this keyword. This annotation affects the
behavior of `additionalProperties` and `unevaluatedProperties`.
matched by at least one property under this keyword.

Omitting this keyword has the same assertion behavior as an empty object.
The presence of this keyword affects the behaviors of
[`additionalProperties`(#additionalproperties) and [`unevaluatedProperties`](#unevaluatedproperties).

##### `additionalProperties` {#additionalproperties}

The value of `additionalProperties` MUST be a valid JSON Schema.

The behavior of this keyword depends on the presence and annotation results of
`properties` and `patternProperties` within the same schema object. Validation
with `additionalProperties` applies only to the child values of instance names
that do not appear in the annotation results of either `properties` or
`patternProperties`.
The behavior of this keyword depends on the presence of `properties` and
`patternProperties` within the same schema object. Validation with
`additionalProperties` applies only to the property values for which neither
`properties` nor `patternProperties` apply.

For all such properties, validation succeeds if the child instance validates
against the `additionalProperties` schema.

The annotation result of this keyword is the set of instance property names
validated by this keyword's subschema. This annotation affects the behavior of
`unevaluatedProperties`.

Omitting this keyword has the same assertion behavior as an empty schema.

Implementations MAY choose to implement or optimize this keyword in another way
that produces the same effect, such as by directly checking the names in
`properties` and the patterns in `patternProperties` against the instance
property set. Implementations that do not support annotation collection MUST do
so.[^12]

[^12]: In defining this option, it seems there is the potential for ambiguity in
the output format. The ambiguity does not affect validation results, but it does
affect the resulting output format. The ambiguity allows for multiple valid
output results depending on whether annotations are used or a solution that
"produces the same effect" as draft-07. It is understood that annotations from
failing schemas are dropped. See our [Decision
Record](https://github.com/json-schema-org/json-schema-spec/tree/HEAD/adr/2022-04-08-cref-for-ambiguity-and-fix-later-gh-spec-issue-1172.md)
for further details.
The annotation result of this keyword is the set of instance property names
validated by this keyword's subschema.

The presence of this keyword affects the behavior of
[`unevaluatedProperties`](#unevaluatedproperties).

##### `propertyNames`

Expand Down Expand Up @@ -1784,7 +1773,8 @@ keyword's annotation causes `contains` to assume a minimum value of 1.

The value of this keyword MUST be a valid JSON Schema.

This keyword applies its subschema to array elements.
This keyword applies to array instances by applying its subschema to the array's
elements.

An instance is valid against `contains` if the number of elements that are valid
against its subschema is with the inclusive range of the minimum and (if any)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be "... is within the ...", but doesn't relate to this PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand. Can you elaborate?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, you're commenting on a line I didn't change. Yeah, I think you're right. Will update.

Expand All @@ -1798,24 +1788,26 @@ 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 `minContains` 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 indexes to
This keyword produces an annotation value which is an array of the indices for
which this keyword validates successfully when applying its subschema, in
ascending order. The value MAY be a boolean `true` if the subschema validates
successfully when applied to every index of the instance. The annotation MUST be
present if the instance array to which this keyword's schema applies
is empty.

This annotation affects the behavior of `unevaluatedItems`.
The presence of this keyword affects the behavior of
[`unevaluatedItems`](#unevaluateditems).

Under most circumstances, the `contains` subschema MAY be short-circuited.
However, for the following cases, the `contains` subschema MUST be applied to
every array element.

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.
- If `unevaluatedItems` appears in any subschema in the dynamic scope that
applies to the same instance location, to ensure that all evaluated items are
accounted for.
- When collecting annotations, to ensure that all annotations are found.

## Keywords for Unevaluated Locations
## Keywords for Unevaluated Locations {#unevaluated}
karenetheridge marked this conversation as resolved.
Show resolved Hide resolved

The purpose of these keywords is to enable schema authors to apply subschemas to
array items or object properties that have not been successfully evaluated
Expand All @@ -1831,16 +1823,16 @@ If an item in an array or an object property is "successfully evaluated", it is
logically considered to be valid in terms of the representation of the object or
array that's expected. For example if a subschema represents a car, which
requires between 2-4 wheels, and the value of "wheels" is 6, the instance object
is not "evaluated" to be a car, and the "wheels" property is considered
"unevaluated (successfully as a known thing)", and does not retain any
annotations.
is not "evaluated" to be a car, and thus the "wheels" property is considered
"unevaluated".

Recall that adjacent keywords are keywords within the same schema object, and
that the dynamic-scope subschemas include reference targets as well as lexical
subschemas.

The behavior of these keywords depend on the annotation results of adjacent
keywords that apply to the instance location being validated.
The behaviors of these keywords depend on adjacent keywords as well as any
keywords in successfully validated subschemas that apply to the same instance
location.

### Keyword Independence

Expand All @@ -1856,62 +1848,52 @@ outcomes. However, these keywords are notable exceptions:

The value of `unevaluatedItems` MUST be a valid JSON Schema.

The behavior of this keyword depends on the annotation results of adjacent
keywords that apply to the instance location being validated. Specifically, the
annotations from `prefixItems`, `items`, and `contains`, which can come from
those keywords when they are adjacent to the `unevaluatedItems` keyword. Those
three annotations, as well as `unevaluatedItems`, can also result from any and
all adjacent [in-place applicator](#in-place) keywords. This includes but is not
limited to the in-place applicators defined in this document.

If no relevant annotations are present, the `unevaluatedItems` subschema MUST be
applied to all locations in the array. If a boolean true value is present from
any of the relevant annotations, `unevaluatedItems` MUST be ignored. Otherwise,
the subschema MUST be applied to any index greater than the largest annotation
value for `prefixItems`, which does not appear in any annotation value for
`contains`.

This means that `prefixItems`, `items`, `contains`, and all in-place applicators
MUST be evaluated before this keyword can be evaluated. Authors of extension
keywords MUST NOT define an in-place applicator that would need to be evaluated
after this keyword.
This keyword applies to array instances by applying its subschema to the array's
elements.

The behavior of this keyword depends on all adjacent keywords as well as
keywords in successfully validated subschemas that apply to the same instance
location by evaluating the instance's elements. This includes, but is not
limited to, `prefixItems`, `items`, and `contains`, itself, and all
[in-place applicators](#in-place) defined in this document.

This keyword applies its subschema to any array elements which have not been
deemed "evaluated" per {{unevaluated}}. Validation passes if the keyword's
subschema validates against all applicable array elements.

If the `unevaluatedItems` subschema is applied to any positions within the
instance array, it produces an annotation result of boolean true, analogous to
the behavior of `items`. This annotation affects the behavior of
`unevaluatedItems` in parent schemas.
the behavior of `items`.

The presence of this keyword affects the behavior of other `unevaluatedItems`
keywords found earlier in the dynamic scope that apply to the same instance
location.

Omitting this keyword has the same assertion behavior as an empty schema.

### `unevaluatedProperties` {#unevaluatedproperties}

The value of `unevaluatedProperties` MUST be a valid JSON Schema.

The behavior of this keyword depends on the annotation results of adjacent
keywords that apply to the instance location being validated. Specifically, the
annotations from `properties`, `patternProperties`, and `additionalProperties`,
which can come from those keywords when they are adjacent to the
`unevaluatedProperties` keyword. Those four annotations, as well as
`unevaluatedProperties`, can also result from any and all adjacent [in-place
applicator](#in-place) keywords. This includes but is not limited to the
in-place applicators defined in this document.
This keyword applies to object instances by applying its subschema to the object's
property values.

Validation with `unevaluatedProperties` applies only to the child values of
instance names that do not appear in the `properties`, `patternProperties`,
`additionalProperties`, or `unevaluatedProperties` annotation results that apply
to the instance location being validated.
The behavior of this keyword depends on all adjacent keywords as well as
keywords in successfully validated subschemas that apply to the same instance
location by evaluating the instance's property values. This includes, but is not limited
to, `properties`, `patternProperties`, and `additionalProperties`, itself, and
all [in-place applicators](#in-place) defined in this document.

For all such properties, validation succeeds if the child instance validates
against the `unevaluatedProperties` schema.

This means that `properties`, `patternProperties`, `additionalProperties`, and
all in-place applicators MUST be evaluated before this keyword can be evaluated.
Authors of extension keywords MUST NOT define an in-place applicator that would
need to be evaluated after this keyword.
This keyword applies its subschema to any property values which have not been
deemed "evaluated" per {{unevaluated}}. Validation passes if the keyword's
subschema validates against all applicable property values.

The annotation result of this keyword is the set of instance property names
validated by this keyword's subschema. This annotation affects the behavior of
`unevaluatedProperties` in parent schemas.
validated by this keyword's subschema.

The presence of this keyword affects the behavior of other `unevaluatedProperties`
keywords found earlier in the dynamic scope that apply to the same instance
location.

Omitting this keyword has the same assertion behavior as an empty schema.

Expand Down
Loading