Skip to content

Commit c2a935d

Browse files
authored
Add full documentation for 2019-09 (#298)
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
1 parent 637a898 commit c2a935d

62 files changed

Lines changed: 5092 additions & 46 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

content/2019-09/applicator/additionalItems.markdown

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,122 @@ related:
3737
- vocabulary: applicator
3838
keyword: unevaluatedItems
3939
---
40+
41+
The [`additionalItems`]({{< ref "2019-09/applicator/additionalitems" >}})
42+
keyword restricts array instance items not described by the _sibling_
43+
[`items`]({{< ref "2019-09/applicator/items" >}}) keyword (when [`items`]({{<
44+
ref "2019-09/applicator/items" >}}) is in array form), to validate against the
45+
given subschema. Whether this keyword was evaluated against any item of the
46+
array instance is reported using annotations.
47+
48+
{{<common-pitfall>}}This keyword **only** has an effect when the sibling
49+
[`items`]({{< ref "2019-09/applicator/items" >}}) keyword is set to an array of
50+
schemas. If [`items`]({{< ref "2019-09/applicator/items" >}}) is not present or
51+
is set to a schema (not an array of schemas), [`additionalItems`]({{< ref
52+
"2019-09/applicator/additionalitems" >}}) has no effect and is ignored.{{</common-pitfall>}}
53+
54+
{{<common-pitfall>}}This keyword does not prevent an array instance from being
55+
empty or having fewer items than the [`items`]({{< ref
56+
"2019-09/applicator/items" >}}) array. If needed, use the [`minItems`]({{< ref
57+
"2019-09/validation/minitems" >}}) keyword to assert on the minimum bounds of
58+
the array.{{</common-pitfall>}}
59+
60+
{{<constraint-warning `array`>}}
61+
62+
## Examples
63+
64+
{{<schema `A schema that constrains array instances to start with a boolean item followed by a number item, with only string items allowed beyond that`>}}
65+
{
66+
"$schema": "https://json-schema.org/draft/2019-09/schema",
67+
"items": [ { "type": "boolean" }, { "type": "number" } ],
68+
"additionalItems": { "type": "string" }
69+
}
70+
{{</schema>}}
71+
72+
{{<instance-pass `An array value that consists of a boolean item followed by a number item is valid`>}}
73+
[ false, 35 ]
74+
{{</instance-pass>}}
75+
76+
{{<instance-annotation>}}
77+
{ "keyword": "/items", "instance": "", "value": true }
78+
{{</instance-annotation>}}
79+
80+
{{<instance-pass `An array value that consists of a boolean item followed by a number item and string items is valid`>}}
81+
[ false, 35, "foo", "bar" ]
82+
{{</instance-pass>}}
83+
84+
{{<instance-annotation>}}
85+
{ "keyword": "/items", "instance": "", "value": 1 }
86+
{ "keyword": "/additionalItems", "instance": "", "value": true }
87+
{{</instance-annotation>}}
88+
89+
{{<instance-fail `An array value that consists of a boolean item followed by a number item and non-string items is invalid`>}}
90+
[ false, 35, { "foo": "bar" } ]
91+
{{</instance-fail>}}
92+
93+
{{<instance-pass `An empty array value is valid`>}}
94+
[]
95+
{{</instance-pass>}}
96+
97+
{{<instance-pass `A non-array value is valid`>}}
98+
"Hello World"
99+
{{</instance-pass>}}
100+
101+
{{<schema `A schema that prevents additional items beyond the tuple`>}}
102+
{
103+
"$schema": "https://json-schema.org/draft/2019-09/schema",
104+
"items": [ { "type": "boolean" }, { "type": "number" } ],
105+
"additionalItems": false
106+
}
107+
{{</schema>}}
108+
109+
{{<instance-pass `An array value with exactly two items matching the tuple is valid`>}}
110+
[ false, 35 ]
111+
{{</instance-pass>}}
112+
113+
{{<instance-annotation>}}
114+
{ "keyword": "/items", "instance": "", "value": true }
115+
{{</instance-annotation>}}
116+
117+
{{<instance-fail `An array value with items beyond the tuple is invalid`>}}
118+
[ false, 35, "foo" ]
119+
{{</instance-fail>}}
120+
121+
{{<schema `A schema that describes open items and additional items leads to the additional items schema being ignored`>}}
122+
{
123+
"$schema": "https://json-schema.org/draft/2019-09/schema",
124+
"items": { "type": "number" },
125+
"additionalItems": { "type": "string" }
126+
}
127+
{{</schema>}}
128+
129+
{{<instance-pass `An array value with only numbers is valid`>}}
130+
[ 1, 2, 3 ]
131+
{{</instance-pass>}}
132+
133+
{{<instance-annotation>}}
134+
{ "keyword": "/items", "instance": "", "value": true }
135+
{{</instance-annotation>}}
136+
137+
{{<instance-pass `An array value with numbers and strings is valid as the keyword is ignored`>}}
138+
[ 1, 2, "foo" ]
139+
{{</instance-pass>}}
140+
141+
{{<instance-annotation>}}
142+
{ "keyword": "/items", "instance": "", "value": true }
143+
{{</instance-annotation>}}
144+
145+
{{<schema `A schema with only additional items definitions leads to the additional items schema being ignored`>}}
146+
{
147+
"$schema": "https://json-schema.org/draft/2019-09/schema",
148+
"additionalItems": { "type": "string" }
149+
}
150+
{{</schema>}}
151+
152+
{{<instance-pass `Any array is valid`>}}
153+
[ 1, 2, 3 ]
154+
{{</instance-pass>}}
155+
156+
{{<instance-pass `A non-array value is valid`>}}
157+
"Hello World"
158+
{{</instance-pass>}}

content/2019-09/applicator/additionalProperties.markdown

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -41,36 +41,36 @@ related:
4141
keyword: unevaluatedProperties
4242
---
4343

44-
The `additionalProperties` keyword restricts object instance properties not
45-
described by the _sibling_ [`properties`]({{< ref
46-
"2019-09/applicator/properties"
47-
>}}) and [`patternProperties`]({{< ref "2019-09/applicator/patternproperties"
48-
>}}) keywords (if any), to validate against the given subschema. Information
49-
about the properties that this keyword was evaluated for is reported using
50-
annotations.
44+
The [`additionalProperties`]({{< ref
45+
"2019-09/applicator/additionalproperties" >}}) keyword restricts object instance
46+
properties not described by the _sibling_ [`properties`]({{< ref
47+
"2019-09/applicator/properties" >}}) and [`patternProperties`]({{< ref
48+
"2019-09/applicator/patternproperties" >}}) keywords (if any), to validate
49+
against the given subschema. Information about the properties that this keyword
50+
was evaluated for is reported using annotations.
5151

5252
{{<common-pitfall>}}The use of the [`properties`]({{< ref
53-
"2019-09/applicator/properties" >}}) keyword **does not prevent the presence of
54-
other properties** in the object instance and **does not enforce the presence
55-
of the declared properties**. In other words, additional data that is not
56-
explicitly prohibited is permitted by default. This is intended behaviour to
57-
ease schema evolution (open schemas are backwards compatible by default) and to
58-
enable highly-expressive constraint-driven schemas.
59-
60-
If you want to restrict instances to only contain the properties you declared,
61-
you must set this keyword to the boolean schema `false`, and if you want to
62-
enforce the presence of certain properties, you must use the [`required`]({{<
63-
ref "2019-09/validation/required" >}}) keyword accordingly.
53+
"2019-09/applicator/properties" >}}) keyword **does not prevent the presence
54+
of other properties** in the object instance and **does not enforce the
55+
presence of the declared properties**. In other words, additional data that
56+
is not explicitly prohibited is permitted by default. This is intended
57+
behaviour to ease schema evolution (open schemas are backwards compatible by
58+
default) and to enable highly-expressive constraint-driven schemas.
59+
60+
If you want to restrict instances to only contain the properties you
61+
declared, you must set this keyword to the boolean schema `false`, and if you
62+
want to enforce the presence of certain properties, you must use the
63+
[`required`]({{< ref "2019-09/validation/required" >}}) keyword accordingly.
6464
{{</common-pitfall>}}
6565

6666
{{<learning-more>}}While the most common use of this keyword is setting it to
67-
the boolean schema `false` to prevent additional properties, it is possible to
68-
set it to a satisfiable schema. Doing this, while omitting the
67+
the boolean schema `false` to prevent additional properties, it is possible
68+
to set it to a satisfiable schema. Doing this, while omitting the
6969
[`properties`]({{< ref "2019-09/applicator/properties" >}}) and
7070
[`patternProperties`]({{< ref "2019-09/applicator/patternproperties" >}})
7171
keywords, is an elegant way of describing how the value of every property in
72-
the object instance must look like independently of its
73-
name.{{</learning-more>}}
72+
the object instance must look like independently of its name.
73+
{{</learning-more>}}
7474

7575
{{<constraint-warning `object`>}}
7676

content/2019-09/applicator/allOf.markdown

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,22 @@ conjunction](https://en.wikipedia.org/wiki/Logical_conjunction) (AND)
3535
operation, as instances are valid if they satisfy every constraint of every
3636
subschema (the intersection of the constraints).
3737

38-
{{<common-pitfall>}} Wrapping a single instance of the [`$ref`](../../core/ref)
39-
or [`$recursiveRef`](../../core/recursiveref) keyword in an `allOf` operator is
40-
an anti-pattern.
38+
{{<common-pitfall>}} Wrapping a single instance of the [`$ref`]({{< ref
39+
"2019-09/core/ref" >}}) or [`$recursiveRef`]({{< ref
40+
"2019-09/core/recursiveref" >}}) keyword in an `allOf` operator is an
41+
anti-pattern.
4142

4243
This practice has historical roots. In JSON Schema [Draft 7](/draft7) and
43-
earlier versions, any subschema declaring the `$ref` keyword was considered to
44-
be a _reference object_ and any other sibling keyword was silently ignored. As
45-
a consequence, subschemas with references that made use of other keywords had
46-
to artificially wrap the reference into its own subschema.
47-
{{</common-pitfall>}}
44+
earlier versions, any subschema declaring the [`$ref`]({{< ref
45+
"2019-09/core/ref" >}}) keyword was considered to be a _reference object_ and
46+
any other sibling keyword was silently ignored. As a consequence, subschemas
47+
with references that made use of other keywords had to artificially wrap the
48+
reference into its own subschema. {{</common-pitfall>}}
4849

4950
{{<best-practice>}}This keyword typically has a single use case: combining
5051
_multiple_ schemas through the use of (internal or external) references. If
51-
this is not the case, prefer elevating the keywords of every subschema to the
52-
outer schema and avoid using this keyword. {{</best-practice>}}
52+
this is not the case, prefer elevating the keywords of every subschema to
53+
the outer schema and avoid using this keyword. {{</best-practice>}}
5354

5455
This keyword is equivalent to the `&&` operator found in most programming
5556
languages. For example:

content/2019-09/applicator/anyOf.markdown

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,153 @@ related:
2525
- vocabulary: applicator
2626
keyword: not
2727
---
28+
29+
The {{<link keyword="anyOf" vocabulary="applicator">}} keyword restricts
30+
instances to validate against _at least one_ (but potentially multiple) of the
31+
given subschemas. This keyword represents a [logical
32+
disjunction](https://en.wikipedia.org/wiki/Logical_disjunction) (OR)
33+
operation, as instances are valid if they satisfy the constraints of one or
34+
more subschemas (the union of the constraints).
35+
36+
{{<learning-more>}}Keep in mind that when collecting annotations, the JSON
37+
Schema implementation will need to exhaustively evaluate every subschema past
38+
the first match instead of short-circuiting validation, potentially
39+
introducing additional computational overhead.
40+
41+
For example, consider 3 subschemas where the instance validates against the
42+
first. When not collecting annotations, validation will stop after evaluating
43+
the first subschema. However, when collecting annotations, evaluation will
44+
have to proceed past the first subschema in case the others emit
45+
annotations.{{</learning-more>}}
46+
47+
This keyword is equivalent to the `||` operator found in most programming
48+
languages. For example:
49+
50+
```c
51+
bool valid = A || B || C;
52+
```
53+
54+
As a reference, the following boolean [truth
55+
table](https://en.wikipedia.org/wiki/Truth_table) considers the evaluation
56+
result of this keyword given 3 subschemas: A, B, and C.
57+
58+
<table class="table table-borderless border">
59+
<thead>
60+
<tr class="table-light">
61+
<th><code>anyOf</code></th>
62+
<th>Subschema A</th>
63+
<th>Subschema B</th>
64+
<th>Subschema C</th>
65+
</tr>
66+
</thead>
67+
<tbody>
68+
<tr class="table-danger">
69+
<td class="fw-bold"><i class="bi bi-x-circle-fill me-1"></i> Invalid</td>
70+
<td><i class="bi bi-x-circle"></i> Invalid</td>
71+
<td><i class="bi bi-x-circle"></i> Invalid</td>
72+
<td><i class="bi bi-x-circle"></i> Invalid</td>
73+
</tr>
74+
<tr class="table-success">
75+
<td class="fw-bold"><i class="bi bi-check-circle-fill me-1"></i> Valid</td>
76+
<td><i class="bi bi-x-circle"></i> Invalid</td>
77+
<td><i class="bi bi-x-circle"></i> Invalid</td>
78+
<td><i class="bi bi-check-circle"></i> Valid</td>
79+
</tr>
80+
<tr class="table-success">
81+
<td class="fw-bold"><i class="bi bi-check-circle-fill me-1"></i> Valid</td>
82+
<td><i class="bi bi-x-circle"></i> Invalid</td>
83+
<td><i class="bi bi-check-circle"></i> Valid</td>
84+
<td><i class="bi bi-x-circle"></i> Invalid</td>
85+
</tr>
86+
<tr class="table-success">
87+
<td class="fw-bold"><i class="bi bi-check-circle-fill me-1"></i> Valid</td>
88+
<td><i class="bi bi-x-circle"></i> Invalid</td>
89+
<td><i class="bi bi-check-circle"></i> Valid</td>
90+
<td><i class="bi bi-check-circle"></i> Valid</td>
91+
</tr>
92+
<tr class="table-success">
93+
<td class="fw-bold"><i class="bi bi-check-circle-fill me-1"></i> Valid</td>
94+
<td><i class="bi bi-check-circle"></i> Valid</td>
95+
<td><i class="bi bi-x-circle"></i> Invalid</td>
96+
<td><i class="bi bi-x-circle"></i> Invalid</td>
97+
</tr>
98+
<tr class="table-success">
99+
<td class="fw-bold"><i class="bi bi-check-circle-fill me-1"></i> Valid</td>
100+
<td><i class="bi bi-check-circle"></i> Valid</td>
101+
<td><i class="bi bi-x-circle"></i> Invalid</td>
102+
<td><i class="bi bi-check-circle"></i> Valid</td>
103+
</tr>
104+
<tr class="table-success">
105+
<td class="fw-bold"><i class="bi bi-check-circle-fill me-1"></i> Valid</td>
106+
<td><i class="bi bi-check-circle"></i> Valid</td>
107+
<td><i class="bi bi-check-circle"></i> Valid</td>
108+
<td><i class="bi bi-x-circle"></i> Invalid</td>
109+
</tr>
110+
<tr class="table-success">
111+
<td class="fw-bold"><i class="bi bi-check-circle-fill me-1"></i> Valid</td>
112+
<td><i class="bi bi-check-circle"></i> Valid</td>
113+
<td><i class="bi bi-check-circle"></i> Valid</td>
114+
<td><i class="bi bi-check-circle"></i> Valid</td>
115+
</tr>
116+
</tbody>
117+
</table>
118+
119+
## Examples
120+
121+
{{<schema `A schema that constrains object instances to require at least one of the given properties`>}}
122+
{
123+
"$schema": "https://json-schema.org/draft/2019-09/schema",
124+
"anyOf": [
125+
{ "required": [ "foo" ] },
126+
{ "required": [ "bar" ] }
127+
]
128+
}
129+
{{</schema>}}
130+
131+
{{<instance-pass `A value that only matches the first subschema is valid`>}}
132+
{ "foo": 1 }
133+
{{</instance-pass>}}
134+
135+
{{<instance-pass `A value that only matches the second subschema is valid`>}}
136+
{ "bar": 2 }
137+
{{</instance-pass>}}
138+
139+
{{<instance-pass `A value that matches every subschema is valid`>}}
140+
{ "foo": 1, "bar": 2 }
141+
{{</instance-pass>}}
142+
143+
{{<instance-fail `A value that does not match any of the subschemas is invalid`>}}
144+
{ "extra": 4 }
145+
{{</instance-fail>}}
146+
147+
{{<schema `A schema that constrains instances with logical disjunctions that emit annotations`>}}
148+
{
149+
"$schema": "https://json-schema.org/draft/2019-09/schema",
150+
"anyOf": [
151+
{ "title": "Branch #1", "type": "number" },
152+
{ "title": "Branch #2", "type": "string" },
153+
{ "title": "Branch #3", "type": "integer" }
154+
]
155+
}
156+
{{</schema>}}
157+
158+
{{<instance-pass `A value that only matches the first subschema receives the first annotation`>}}
159+
3.14
160+
{{</instance-pass>}}
161+
162+
{{<instance-annotation>}}
163+
{ "keyword": "/anyOf/0/title", "instance": "", "value": [ "Branch #1" ] }
164+
{{</instance-annotation>}}
165+
166+
{{<instance-pass `A value that matches two subschemas receives both annotations`>}}
167+
12345
168+
{{</instance-pass>}}
169+
170+
{{<instance-annotation>}}
171+
{ "keyword": "/anyOf/0/title", "instance": "", "value": [ "Branch #1" ] }
172+
{ "keyword": "/anyOf/2/title", "instance": "", "value": [ "Branch #3" ] }
173+
{{</instance-annotation>}}
174+
175+
{{<instance-fail `A value that does not match any of the subschemas is invalid and receives no annotations`>}}
176+
{ "foo": 1 }
177+
{{</instance-fail>}}

0 commit comments

Comments
 (0)