1[ 2 { 3 "description": "$recursiveRef without $recursiveAnchor works like $ref", 4 "schema": { 5 "$schema": "https://json-schema.org/draft/2019-09/schema", 6 "properties": { 7 "foo": { "$recursiveRef": "#" } 8 }, 9 "additionalProperties": false 10 }, 11 "tests": [ 12 { 13 "description": "match", 14 "data": {"foo": false}, 15 "valid": true 16 }, 17 { 18 "description": "recursive match", 19 "data": { "foo": { "foo": false } }, 20 "valid": true 21 }, 22 { 23 "description": "mismatch", 24 "data": { "bar": false }, 25 "valid": false 26 }, 27 { 28 "description": "recursive mismatch", 29 "data": { "foo": { "bar": false } }, 30 "valid": false 31 } 32 ] 33 }, 34 { 35 "description": "$recursiveRef without using nesting", 36 "schema": { 37 "$schema": "https://json-schema.org/draft/2019-09/schema", 38 "$id": "http://localhost:4242/draft2019-09/recursiveRef2/schema.json", 39 "$defs": { 40 "myobject": { 41 "$id": "myobject.json", 42 "$recursiveAnchor": true, 43 "anyOf": [ 44 { "type": "string" }, 45 { 46 "type": "object", 47 "additionalProperties": { "$recursiveRef": "#" } 48 } 49 ] 50 } 51 }, 52 "anyOf": [ 53 { "type": "integer" }, 54 { "$ref": "#/$defs/myobject" } 55 ] 56 }, 57 "tests": [ 58 { 59 "description": "integer matches at the outer level", 60 "data": 1, 61 "valid": true 62 }, 63 { 64 "description": "single level match", 65 "data": { "foo": "hi" }, 66 "valid": true 67 }, 68 { 69 "description": "integer does not match as a property value", 70 "data": { "foo": 1 }, 71 "valid": false 72 }, 73 { 74 "description": "two levels, properties match with inner definition", 75 "data": { "foo": { "bar": "hi" } }, 76 "valid": true 77 }, 78 { 79 "description": "two levels, no match", 80 "data": { "foo": { "bar": 1 } }, 81 "valid": false 82 } 83 ] 84 }, 85 { 86 "description": "$recursiveRef with nesting", 87 "schema": { 88 "$schema": "https://json-schema.org/draft/2019-09/schema", 89 "$id": "http://localhost:4242/draft2019-09/recursiveRef3/schema.json", 90 "$recursiveAnchor": true, 91 "$defs": { 92 "myobject": { 93 "$id": "myobject.json", 94 "$recursiveAnchor": true, 95 "anyOf": [ 96 { "type": "string" }, 97 { 98 "type": "object", 99 "additionalProperties": { "$recursiveRef": "#" } 100 } 101 ] 102 } 103 }, 104 "anyOf": [ 105 { "type": "integer" }, 106 { "$ref": "#/$defs/myobject" } 107 ] 108 }, 109 "tests": [ 110 { 111 "description": "integer matches at the outer level", 112 "data": 1, 113 "valid": true 114 }, 115 { 116 "description": "single level match", 117 "data": { "foo": "hi" }, 118 "valid": true 119 }, 120 { 121 "description": "integer now matches as a property value", 122 "data": { "foo": 1 }, 123 "valid": true 124 }, 125 { 126 "description": "two levels, properties match with inner definition", 127 "data": { "foo": { "bar": "hi" } }, 128 "valid": true 129 }, 130 { 131 "description": "two levels, properties match with $recursiveRef", 132 "data": { "foo": { "bar": 1 } }, 133 "valid": true 134 } 135 ] 136 }, 137 { 138 "description": "$recursiveRef with $recursiveAnchor: false works like $ref", 139 "schema": { 140 "$schema": "https://json-schema.org/draft/2019-09/schema", 141 "$id": "http://localhost:4242/draft2019-09/recursiveRef4/schema.json", 142 "$recursiveAnchor": false, 143 "$defs": { 144 "myobject": { 145 "$id": "myobject.json", 146 "$recursiveAnchor": false, 147 "anyOf": [ 148 { "type": "string" }, 149 { 150 "type": "object", 151 "additionalProperties": { "$recursiveRef": "#" } 152 } 153 ] 154 } 155 }, 156 "anyOf": [ 157 { "type": "integer" }, 158 { "$ref": "#/$defs/myobject" } 159 ] 160 }, 161 "tests": [ 162 { 163 "description": "integer matches at the outer level", 164 "data": 1, 165 "valid": true 166 }, 167 { 168 "description": "single level match", 169 "data": { "foo": "hi" }, 170 "valid": true 171 }, 172 { 173 "description": "integer does not match as a property value", 174 "data": { "foo": 1 }, 175 "valid": false 176 }, 177 { 178 "description": "two levels, properties match with inner definition", 179 "data": { "foo": { "bar": "hi" } }, 180 "valid": true 181 }, 182 { 183 "description": "two levels, integer does not match as a property value", 184 "data": { "foo": { "bar": 1 } }, 185 "valid": false 186 } 187 ] 188 }, 189 { 190 "description": "$recursiveRef with no $recursiveAnchor works like $ref", 191 "schema": { 192 "$schema": "https://json-schema.org/draft/2019-09/schema", 193 "$id": "http://localhost:4242/draft2019-09/recursiveRef5/schema.json", 194 "$defs": { 195 "myobject": { 196 "$id": "myobject.json", 197 "$recursiveAnchor": false, 198 "anyOf": [ 199 { "type": "string" }, 200 { 201 "type": "object", 202 "additionalProperties": { "$recursiveRef": "#" } 203 } 204 ] 205 } 206 }, 207 "anyOf": [ 208 { "type": "integer" }, 209 { "$ref": "#/$defs/myobject" } 210 ] 211 }, 212 "tests": [ 213 { 214 "description": "integer matches at the outer level", 215 "data": 1, 216 "valid": true 217 }, 218 { 219 "description": "single level match", 220 "data": { "foo": "hi" }, 221 "valid": true 222 }, 223 { 224 "description": "integer does not match as a property value", 225 "data": { "foo": 1 }, 226 "valid": false 227 }, 228 { 229 "description": "two levels, properties match with inner definition", 230 "data": { "foo": { "bar": "hi" } }, 231 "valid": true 232 }, 233 { 234 "description": "two levels, integer does not match as a property value", 235 "data": { "foo": { "bar": 1 } }, 236 "valid": false 237 } 238 ] 239 }, 240 { 241 "description": "$recursiveRef with no $recursiveAnchor in the initial target schema resource", 242 "schema": { 243 "$schema": "https://json-schema.org/draft/2019-09/schema", 244 "$id": "http://localhost:4242/draft2019-09/recursiveRef6/base.json", 245 "$recursiveAnchor": true, 246 "anyOf": [ 247 { "type": "boolean" }, 248 { 249 "type": "object", 250 "additionalProperties": { 251 "$id": "http://localhost:4242/draft2019-09/recursiveRef6/inner.json", 252 "$comment": "there is no $recursiveAnchor: true here, so we do NOT recurse to the base", 253 "anyOf": [ 254 { "type": "integer" }, 255 { "type": "object", "additionalProperties": { "$recursiveRef": "#" } } 256 ] 257 } 258 } 259 ] 260 }, 261 "tests": [ 262 { 263 "description": "leaf node does not match; no recursion", 264 "data": { "foo": true }, 265 "valid": false 266 }, 267 { 268 "description": "leaf node matches: recursion uses the inner schema", 269 "data": { "foo": { "bar": 1 } }, 270 "valid": true 271 }, 272 { 273 "description": "leaf node does not match: recursion uses the inner schema", 274 "data": { "foo": { "bar": true } }, 275 "valid": false 276 } 277 ] 278 }, 279 { 280 "description": "$recursiveRef with no $recursiveAnchor in the outer schema resource", 281 "schema": { 282 "$schema": "https://json-schema.org/draft/2019-09/schema", 283 "$id": "http://localhost:4242/draft2019-09/recursiveRef7/base.json", 284 "anyOf": [ 285 { "type": "boolean" }, 286 { 287 "type": "object", 288 "additionalProperties": { 289 "$id": "http://localhost:4242/draft2019-09/recursiveRef7/inner.json", 290 "$recursiveAnchor": true, 291 "anyOf": [ 292 { "type": "integer" }, 293 { "type": "object", "additionalProperties": { "$recursiveRef": "#" } } 294 ] 295 } 296 } 297 ] 298 }, 299 "tests": [ 300 { 301 "description": "leaf node does not match; no recursion", 302 "data": { "foo": true }, 303 "valid": false 304 }, 305 { 306 "description": "leaf node matches: recursion only uses inner schema", 307 "data": { "foo": { "bar": 1 } }, 308 "valid": true 309 }, 310 { 311 "description": "leaf node does not match: recursion only uses inner schema", 312 "data": { "foo": { "bar": true } }, 313 "valid": false 314 } 315 ] 316 }, 317 { 318 "description": "multiple dynamic paths to the $recursiveRef keyword", 319 "schema": { 320 "$schema": "https://json-schema.org/draft/2019-09/schema", 321 "$id": "https://example.com/recursiveRef8_main.json", 322 "$defs": { 323 "inner": { 324 "$id": "recursiveRef8_inner.json", 325 "$recursiveAnchor": true, 326 "title": "inner", 327 "additionalProperties": { 328 "$recursiveRef": "#" 329 } 330 } 331 }, 332 "if": { 333 "propertyNames": { 334 "pattern": "^[a-m]" 335 } 336 }, 337 "then": { 338 "title": "any type of node", 339 "$id": "recursiveRef8_anyLeafNode.json", 340 "$recursiveAnchor": true, 341 "$ref": "recursiveRef8_inner.json" 342 }, 343 "else": { 344 "title": "integer node", 345 "$id": "recursiveRef8_integerNode.json", 346 "$recursiveAnchor": true, 347 "type": [ "object", "integer" ], 348 "$ref": "recursiveRef8_inner.json" 349 } 350 }, 351 "tests": [ 352 { 353 "description": "recurse to anyLeafNode - floats are allowed", 354 "data": { "alpha": 1.1 }, 355 "valid": true 356 }, 357 { 358 "description": "recurse to integerNode - floats are not allowed", 359 "data": { "november": 1.1 }, 360 "valid": false 361 } 362 ] 363 }, 364 { 365 "description": "dynamic $recursiveRef destination (not predictable at schema compile time)", 366 "schema": { 367 "$schema": "https://json-schema.org/draft/2019-09/schema", 368 "$id": "https://example.com/main.json", 369 "$defs": { 370 "inner": { 371 "$id": "inner.json", 372 "$recursiveAnchor": true, 373 "title": "inner", 374 "additionalProperties": { 375 "$recursiveRef": "#" 376 } 377 } 378 379 }, 380 "if": { "propertyNames": { "pattern": "^[a-m]" } }, 381 "then": { 382 "title": "any type of node", 383 "$id": "anyLeafNode.json", 384 "$recursiveAnchor": true, 385 "$ref": "main.json#/$defs/inner" 386 }, 387 "else": { 388 "title": "integer node", 389 "$id": "integerNode.json", 390 "$recursiveAnchor": true, 391 "type": [ "object", "integer" ], 392 "$ref": "main.json#/$defs/inner" 393 } 394 }, 395 "tests": [ 396 { 397 "description": "numeric node", 398 "data": { "alpha": 1.1 }, 399 "valid": true 400 }, 401 { 402 "description": "integer node", 403 "data": { "november": 1.1 }, 404 "valid": false 405 } 406 ] 407 } 408] 409