1[ 2 { 3 "description": "A $dynamicRef to a $dynamicAnchor in the same schema resource behaves like a normal $ref to an $anchor", 4 "schema": { 5 "$schema": "https://json-schema.org/draft/2020-12/schema", 6 "$id": "https://test.json-schema.org/dynamicRef-dynamicAnchor-same-schema/root", 7 "type": "array", 8 "items": { "$dynamicRef": "#items" }, 9 "$defs": { 10 "foo": { 11 "$dynamicAnchor": "items", 12 "type": "string" 13 } 14 } 15 }, 16 "tests": [ 17 { 18 "description": "An array of strings is valid", 19 "data": ["foo", "bar"], 20 "valid": true 21 }, 22 { 23 "description": "An array containing non-strings is invalid", 24 "data": ["foo", 42], 25 "valid": false 26 } 27 ] 28 }, 29 { 30 "description": "A $dynamicRef to an $anchor in the same schema resource behaves like a normal $ref to an $anchor", 31 "schema": { 32 "$schema": "https://json-schema.org/draft/2020-12/schema", 33 "$id": "https://test.json-schema.org/dynamicRef-anchor-same-schema/root", 34 "type": "array", 35 "items": { "$dynamicRef": "#items" }, 36 "$defs": { 37 "foo": { 38 "$anchor": "items", 39 "type": "string" 40 } 41 } 42 }, 43 "tests": [ 44 { 45 "description": "An array of strings is valid", 46 "data": ["foo", "bar"], 47 "valid": true 48 }, 49 { 50 "description": "An array containing non-strings is invalid", 51 "data": ["foo", 42], 52 "valid": false 53 } 54 ] 55 }, 56 { 57 "description": "A $ref to a $dynamicAnchor in the same schema resource behaves like a normal $ref to an $anchor", 58 "schema": { 59 "$schema": "https://json-schema.org/draft/2020-12/schema", 60 "$id": "https://test.json-schema.org/ref-dynamicAnchor-same-schema/root", 61 "type": "array", 62 "items": { "$ref": "#items" }, 63 "$defs": { 64 "foo": { 65 "$dynamicAnchor": "items", 66 "type": "string" 67 } 68 } 69 }, 70 "tests": [ 71 { 72 "description": "An array of strings is valid", 73 "data": ["foo", "bar"], 74 "valid": true 75 }, 76 { 77 "description": "An array containing non-strings is invalid", 78 "data": ["foo", 42], 79 "valid": false 80 } 81 ] 82 }, 83 { 84 "description": "A $dynamicRef resolves to the first $dynamicAnchor still in scope that is encountered when the schema is evaluated", 85 "schema": { 86 "$schema": "https://json-schema.org/draft/2020-12/schema", 87 "$id": "https://test.json-schema.org/typical-dynamic-resolution/root", 88 "$ref": "list", 89 "$defs": { 90 "foo": { 91 "$dynamicAnchor": "items", 92 "type": "string" 93 }, 94 "list": { 95 "$id": "list", 96 "type": "array", 97 "items": { "$dynamicRef": "#items" }, 98 "$defs": { 99 "items": { 100 "$comment": "This is only needed to satisfy the bookending requirement", 101 "$dynamicAnchor": "items" 102 } 103 } 104 } 105 } 106 }, 107 "tests": [ 108 { 109 "description": "An array of strings is valid", 110 "data": ["foo", "bar"], 111 "valid": true 112 }, 113 { 114 "description": "An array containing non-strings is invalid", 115 "data": ["foo", 42], 116 "valid": false 117 } 118 ] 119 }, 120 { 121 "description": "A $dynamicRef without anchor in fragment behaves identical to $ref", 122 "schema": { 123 "$schema": "https://json-schema.org/draft/2020-12/schema", 124 "$id": "https://test.json-schema.org/dynamicRef-without-anchor/root", 125 "$ref": "list", 126 "$defs": { 127 "foo": { 128 "$dynamicAnchor": "items", 129 "type": "string" 130 }, 131 "list": { 132 "$id": "list", 133 "type": "array", 134 "items": { "$dynamicRef": "#/$defs/items" }, 135 "$defs": { 136 "items": { 137 "$comment": "This is only needed to satisfy the bookending requirement", 138 "$dynamicAnchor": "items", 139 "type": "number" 140 } 141 } 142 } 143 } 144 }, 145 "tests": [ 146 { 147 "description": "An array of strings is invalid", 148 "data": ["foo", "bar"], 149 "valid": false 150 }, 151 { 152 "description": "An array of numbers is valid", 153 "data": [24, 42], 154 "valid": true 155 } 156 ] 157 }, 158 { 159 "description": "A $dynamicRef with intermediate scopes that don't include a matching $dynamicAnchor does not affect dynamic scope resolution", 160 "schema": { 161 "$schema": "https://json-schema.org/draft/2020-12/schema", 162 "$id": "https://test.json-schema.org/dynamic-resolution-with-intermediate-scopes/root", 163 "$ref": "intermediate-scope", 164 "$defs": { 165 "foo": { 166 "$dynamicAnchor": "items", 167 "type": "string" 168 }, 169 "intermediate-scope": { 170 "$id": "intermediate-scope", 171 "$ref": "list" 172 }, 173 "list": { 174 "$id": "list", 175 "type": "array", 176 "items": { "$dynamicRef": "#items" }, 177 "$defs": { 178 "items": { 179 "$comment": "This is only needed to satisfy the bookending requirement", 180 "$dynamicAnchor": "items" 181 } 182 } 183 } 184 } 185 }, 186 "tests": [ 187 { 188 "description": "An array of strings is valid", 189 "data": ["foo", "bar"], 190 "valid": true 191 }, 192 { 193 "description": "An array containing non-strings is invalid", 194 "data": ["foo", 42], 195 "valid": false 196 } 197 ] 198 }, 199 { 200 "description": "An $anchor with the same name as a $dynamicAnchor is not used for dynamic scope resolution", 201 "schema": { 202 "$schema": "https://json-schema.org/draft/2020-12/schema", 203 "$id": "https://test.json-schema.org/dynamic-resolution-ignores-anchors/root", 204 "$ref": "list", 205 "$defs": { 206 "foo": { 207 "$anchor": "items", 208 "type": "string" 209 }, 210 "list": { 211 "$id": "list", 212 "type": "array", 213 "items": { "$dynamicRef": "#items" }, 214 "$defs": { 215 "items": { 216 "$comment": "This is only needed to satisfy the bookending requirement", 217 "$dynamicAnchor": "items" 218 } 219 } 220 } 221 } 222 }, 223 "tests": [ 224 { 225 "description": "Any array is valid", 226 "data": ["foo", 42], 227 "valid": true 228 } 229 ] 230 }, 231 { 232 "description": "A $dynamicRef without a matching $dynamicAnchor in the same schema resource behaves like a normal $ref to $anchor", 233 "schema": { 234 "$schema": "https://json-schema.org/draft/2020-12/schema", 235 "$id": "https://test.json-schema.org/dynamic-resolution-without-bookend/root", 236 "$ref": "list", 237 "$defs": { 238 "foo": { 239 "$dynamicAnchor": "items", 240 "type": "string" 241 }, 242 "list": { 243 "$id": "list", 244 "type": "array", 245 "items": { "$dynamicRef": "#items" }, 246 "$defs": { 247 "items": { 248 "$comment": "This is only needed to give the reference somewhere to resolve to when it behaves like $ref", 249 "$anchor": "items" 250 } 251 } 252 } 253 } 254 }, 255 "tests": [ 256 { 257 "description": "Any array is valid", 258 "data": ["foo", 42], 259 "valid": true 260 } 261 ] 262 }, 263 { 264 "description": "A $dynamicRef with a non-matching $dynamicAnchor in the same schema resource behaves like a normal $ref to $anchor", 265 "schema": { 266 "$schema": "https://json-schema.org/draft/2020-12/schema", 267 "$id": "https://test.json-schema.org/unmatched-dynamic-anchor/root", 268 "$ref": "list", 269 "$defs": { 270 "foo": { 271 "$dynamicAnchor": "items", 272 "type": "string" 273 }, 274 "list": { 275 "$id": "list", 276 "type": "array", 277 "items": { "$dynamicRef": "#items" }, 278 "$defs": { 279 "items": { 280 "$comment": "This is only needed to give the reference somewhere to resolve to when it behaves like $ref", 281 "$anchor": "items", 282 "$dynamicAnchor": "foo" 283 } 284 } 285 } 286 } 287 }, 288 "tests": [ 289 { 290 "description": "Any array is valid", 291 "data": ["foo", 42], 292 "valid": true 293 } 294 ] 295 }, 296 { 297 "description": "A $dynamicRef that initially resolves to a schema with a matching $dynamicAnchor resolves to the first $dynamicAnchor in the dynamic scope", 298 "schema": { 299 "$schema": "https://json-schema.org/draft/2020-12/schema", 300 "$id": "https://test.json-schema.org/relative-dynamic-reference/root", 301 "$dynamicAnchor": "meta", 302 "type": "object", 303 "properties": { 304 "foo": { "const": "pass" } 305 }, 306 "$ref": "extended", 307 "$defs": { 308 "extended": { 309 "$id": "extended", 310 "$dynamicAnchor": "meta", 311 "type": "object", 312 "properties": { 313 "bar": { "$ref": "bar" } 314 } 315 }, 316 "bar": { 317 "$id": "bar", 318 "type": "object", 319 "properties": { 320 "baz": { "$dynamicRef": "extended#meta" } 321 } 322 } 323 } 324 }, 325 "tests": [ 326 { 327 "description": "The recursive part is valid against the root", 328 "data": { 329 "foo": "pass", 330 "bar": { 331 "baz": { "foo": "pass" } 332 } 333 }, 334 "valid": true 335 }, 336 { 337 "description": "The recursive part is not valid against the root", 338 "data": { 339 "foo": "pass", 340 "bar": { 341 "baz": { "foo": "fail" } 342 } 343 }, 344 "valid": false 345 } 346 ] 347 }, 348 { 349 "description": "A $dynamicRef that initially resolves to a schema without a matching $dynamicAnchor behaves like a normal $ref to $anchor", 350 "schema": { 351 "$schema": "https://json-schema.org/draft/2020-12/schema", 352 "$id": "https://test.json-schema.org/relative-dynamic-reference-without-bookend/root", 353 "$dynamicAnchor": "meta", 354 "type": "object", 355 "properties": { 356 "foo": { "const": "pass" } 357 }, 358 "$ref": "extended", 359 "$defs": { 360 "extended": { 361 "$id": "extended", 362 "$anchor": "meta", 363 "type": "object", 364 "properties": { 365 "bar": { "$ref": "bar" } 366 } 367 }, 368 "bar": { 369 "$id": "bar", 370 "type": "object", 371 "properties": { 372 "baz": { "$dynamicRef": "extended#meta" } 373 } 374 } 375 } 376 }, 377 "tests": [ 378 { 379 "description": "The recursive part doesn't need to validate against the root", 380 "data": { 381 "foo": "pass", 382 "bar": { 383 "baz": { "foo": "fail" } 384 } 385 }, 386 "valid": true 387 } 388 ] 389 }, 390 { 391 "description": "multiple dynamic paths to the $dynamicRef keyword", 392 "schema": { 393 "$schema": "https://json-schema.org/draft/2020-12/schema", 394 "$id": "https://test.json-schema.org/dynamic-ref-with-multiple-paths/main", 395 "if": { 396 "properties": { 397 "kindOfList": { "const": "numbers" } 398 }, 399 "required": ["kindOfList"] 400 }, 401 "then": { "$ref": "numberList" }, 402 "else": { "$ref": "stringList" }, 403 404 "$defs": { 405 "genericList": { 406 "$id": "genericList", 407 "properties": { 408 "list": { 409 "items": { "$dynamicRef": "#itemType" } 410 } 411 }, 412 "$defs": { 413 "defaultItemType": { 414 "$comment": "Only needed to satisfy bookending requirement", 415 "$dynamicAnchor": "itemType" 416 } 417 } 418 }, 419 "numberList": { 420 "$id": "numberList", 421 "$defs": { 422 "itemType": { 423 "$dynamicAnchor": "itemType", 424 "type": "number" 425 } 426 }, 427 "$ref": "genericList" 428 }, 429 "stringList": { 430 "$id": "stringList", 431 "$defs": { 432 "itemType": { 433 "$dynamicAnchor": "itemType", 434 "type": "string" 435 } 436 }, 437 "$ref": "genericList" 438 } 439 } 440 }, 441 "tests": [ 442 { 443 "description": "number list with number values", 444 "data": { 445 "kindOfList": "numbers", 446 "list": [1.1] 447 }, 448 "valid": true 449 }, 450 { 451 "description": "number list with string values", 452 "data": { 453 "kindOfList": "numbers", 454 "list": ["foo"] 455 }, 456 "valid": false 457 }, 458 { 459 "description": "string list with number values", 460 "data": { 461 "kindOfList": "strings", 462 "list": [1.1] 463 }, 464 "valid": false 465 }, 466 { 467 "description": "string list with string values", 468 "data": { 469 "kindOfList": "strings", 470 "list": ["foo"] 471 }, 472 "valid": true 473 } 474 ] 475 }, 476 { 477 "description": "after leaving a dynamic scope, it is not used by a $dynamicRef", 478 "schema": { 479 "$schema": "https://json-schema.org/draft/2020-12/schema", 480 "$id": "https://test.json-schema.org/dynamic-ref-leaving-dynamic-scope/main", 481 "if": { 482 "$id": "first_scope", 483 "$defs": { 484 "thingy": { 485 "$comment": "this is first_scope#thingy", 486 "$dynamicAnchor": "thingy", 487 "type": "number" 488 } 489 } 490 }, 491 "then": { 492 "$id": "second_scope", 493 "$ref": "start", 494 "$defs": { 495 "thingy": { 496 "$comment": "this is second_scope#thingy, the final destination of the $dynamicRef", 497 "$dynamicAnchor": "thingy", 498 "type": "null" 499 } 500 } 501 }, 502 "$defs": { 503 "start": { 504 "$comment": "this is the landing spot from $ref", 505 "$id": "start", 506 "$dynamicRef": "inner_scope#thingy" 507 }, 508 "thingy": { 509 "$comment": "this is the first stop for the $dynamicRef", 510 "$id": "inner_scope", 511 "$dynamicAnchor": "thingy", 512 "type": "string" 513 } 514 } 515 }, 516 "tests": [ 517 { 518 "description": "string matches /$defs/thingy, but the $dynamicRef does not stop here", 519 "data": "a string", 520 "valid": false 521 }, 522 { 523 "description": "first_scope is not in dynamic scope for the $dynamicRef", 524 "data": 42, 525 "valid": false 526 }, 527 { 528 "description": "/then/$defs/thingy is the final stop for the $dynamicRef", 529 "data": null, 530 "valid": true 531 } 532 ] 533 }, 534 { 535 "description": "strict-tree schema, guards against misspelled properties", 536 "schema": { 537 "$schema": "https://json-schema.org/draft/2020-12/schema", 538 "$id": "http://localhost:1234/draft2020-12/strict-tree.json", 539 "$dynamicAnchor": "node", 540 541 "$ref": "tree.json", 542 "unevaluatedProperties": false 543 }, 544 "tests": [ 545 { 546 "description": "instance with misspelled field", 547 "data": { 548 "children": [{ 549 "daat": 1 550 }] 551 }, 552 "valid": false 553 }, 554 { 555 "description": "instance with correct field", 556 "data": { 557 "children": [{ 558 "data": 1 559 }] 560 }, 561 "valid": true 562 } 563 ] 564 }, 565 { 566 "description": "tests for implementation dynamic anchor and reference link", 567 "schema": { 568 "$schema": "https://json-schema.org/draft/2020-12/schema", 569 "$id": "http://localhost:1234/draft2020-12/strict-extendible.json", 570 "$ref": "extendible-dynamic-ref.json", 571 "$defs": { 572 "elements": { 573 "$dynamicAnchor": "elements", 574 "properties": { 575 "a": true 576 }, 577 "required": ["a"], 578 "additionalProperties": false 579 } 580 } 581 }, 582 "tests": [ 583 { 584 "description": "incorrect parent schema", 585 "data": { 586 "a": true 587 }, 588 "valid": false 589 }, 590 { 591 "description": "incorrect extended schema", 592 "data": { 593 "elements": [ 594 { "b": 1 } 595 ] 596 }, 597 "valid": false 598 }, 599 { 600 "description": "correct extended schema", 601 "data": { 602 "elements": [ 603 { "a": 1 } 604 ] 605 }, 606 "valid": true 607 } 608 ] 609 }, 610 { 611 "description": "$ref and $dynamicAnchor are independent of order - $defs first", 612 "schema": { 613 "$schema": "https://json-schema.org/draft/2020-12/schema", 614 "$id": "http://localhost:1234/draft2020-12/strict-extendible-allof-defs-first.json", 615 "allOf": [ 616 { 617 "$ref": "extendible-dynamic-ref.json" 618 }, 619 { 620 "$defs": { 621 "elements": { 622 "$dynamicAnchor": "elements", 623 "properties": { 624 "a": true 625 }, 626 "required": ["a"], 627 "additionalProperties": false 628 } 629 } 630 } 631 ] 632 }, 633 "tests": [ 634 { 635 "description": "incorrect parent schema", 636 "data": { 637 "a": true 638 }, 639 "valid": false 640 }, 641 { 642 "description": "incorrect extended schema", 643 "data": { 644 "elements": [ 645 { "b": 1 } 646 ] 647 }, 648 "valid": false 649 }, 650 { 651 "description": "correct extended schema", 652 "data": { 653 "elements": [ 654 { "a": 1 } 655 ] 656 }, 657 "valid": true 658 } 659 ] 660 }, 661 { 662 "description": "$ref and $dynamicAnchor are independent of order - $ref first", 663 "schema": { 664 "$schema": "https://json-schema.org/draft/2020-12/schema", 665 "$id": "http://localhost:1234/draft2020-12/strict-extendible-allof-ref-first.json", 666 "allOf": [ 667 { 668 "$defs": { 669 "elements": { 670 "$dynamicAnchor": "elements", 671 "properties": { 672 "a": true 673 }, 674 "required": ["a"], 675 "additionalProperties": false 676 } 677 } 678 }, 679 { 680 "$ref": "extendible-dynamic-ref.json" 681 } 682 ] 683 }, 684 "tests": [ 685 { 686 "description": "incorrect parent schema", 687 "data": { 688 "a": true 689 }, 690 "valid": false 691 }, 692 { 693 "description": "incorrect extended schema", 694 "data": { 695 "elements": [ 696 { "b": 1 } 697 ] 698 }, 699 "valid": false 700 }, 701 { 702 "description": "correct extended schema", 703 "data": { 704 "elements": [ 705 { "a": 1 } 706 ] 707 }, 708 "valid": true 709 } 710 ] 711 }, 712 { 713 "description": "$ref to $dynamicRef finds detached $dynamicAnchor", 714 "schema": { 715 "$ref": "http://localhost:1234/draft2020-12/detached-dynamicref.json#/$defs/foo" 716 }, 717 "tests": [ 718 { 719 "description": "number is valid", 720 "data": 1, 721 "valid": true 722 }, 723 { 724 "description": "non-number is invalid", 725 "data": "a", 726 "valid": false 727 } 728 ] 729 }, 730 { 731 "description": "$dynamicRef points to a boolean schema", 732 "schema": { 733 "$schema": "https://json-schema.org/draft/2020-12/schema", 734 "$defs": { 735 "true": true, 736 "false": false 737 }, 738 "properties": { 739 "true": { 740 "$dynamicRef": "#/$defs/true" 741 }, 742 "false": { 743 "$dynamicRef": "#/$defs/false" 744 } 745 } 746 }, 747 "tests": [ 748 { 749 "description": "follow $dynamicRef to a true schema", 750 "data": { "true": 1 }, 751 "valid": true 752 }, 753 { 754 "description": "follow $dynamicRef to a false schema", 755 "data": { "false": 1 }, 756 "valid": false 757 } 758 ] 759 } 760] 761