diff --git a/Cargo.lock b/Cargo.lock index c64f7e94..ea22da09 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,30 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "ahash" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" -dependencies = [ - "getrandom 0.2.16", - "once_cell", - "version_check", -] - -[[package]] -name = "ahash" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" -dependencies = [ - "cfg-if", - "getrandom 0.3.4", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "aho-corasick" version = "1.1.4" @@ -100,33 +76,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" -[[package]] -name = "base64-simd" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "781dd20c3aff0bd194fe7d2a977dd92f21c173891f3a03b677359e5fa457e5d5" -dependencies = [ - "simd-abstraction", -] - [[package]] name = "bitflags" version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - [[package]] name = "block-buffer" version = "0.10.4" @@ -152,34 +107,6 @@ version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" -[[package]] -name = "bytecheck" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" -dependencies = [ - "bytecheck_derive", - "ptr_meta", - "simdutf8", -] - -[[package]] -name = "bytecheck_derive" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "bytes" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" - [[package]] name = "cc" version = "1.2.51" @@ -203,9 +130,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ "iana-time-zone", - "js-sys", "num-traits", - "wasm-bindgen", "windows-link", ] @@ -262,7 +187,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.111", + "syn", ] [[package]] @@ -277,35 +202,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" -[[package]] -name = "const-str" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21077772762a1002bb421c3af42ac1725fa56066bfc53d9a55bb79905df2aaf3" -dependencies = [ - "const-str-proc-macro", -] - -[[package]] -name = "const-str-proc-macro" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e1e0fdd2e5d3041e530e1b21158aeeef8b5d0e306bc5c1e3d6cf0930d10e25a" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "convert_case" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -356,66 +252,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "cssparser" -version = "0.33.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9be934d936a0fbed5bcdc01042b770de1398bf79d0e192f49fa7faea0e99281e" -dependencies = [ - "cssparser-macros", - "dtoa-short", - "itoa", - "phf", - "smallvec", -] - -[[package]] -name = "cssparser-color" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556c099a61d85989d7af52b692e35a8d68a57e7df8c6d07563dc0778b3960c9f" -dependencies = [ - "cssparser", -] - -[[package]] -name = "cssparser-macros" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" -dependencies = [ - "quote", - "syn 2.0.111", -] - -[[package]] -name = "dashmap" -version = "5.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" -dependencies = [ - "cfg-if", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", -] - -[[package]] -name = "data-encoding" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" - -[[package]] -name = "data-url" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a30bfce702bcfa94e906ef82421f2c0e61c076ad76030c16ee5d2e9a32fe193" -dependencies = [ - "matches", -] - [[package]] name = "deunicode" version = "1.6.2" @@ -432,60 +268,18 @@ dependencies = [ "crypto-common", ] -[[package]] -name = "dtoa" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6add3b8cff394282be81f3fc1a0605db594ed69890078ca6e2cab1c408bcf04" - -[[package]] -name = "dtoa-short" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" -dependencies = [ - "dtoa", -] - [[package]] name = "dyn-clone" version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - -[[package]] -name = "equivalent" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" - -[[package]] -name = "erased-serde" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c138974f9d5e7fe373eb04df7cae98833802ae4b11c24ac7039a21d5af4b26c" -dependencies = [ - "serde", -] - [[package]] name = "find-msvc-tools" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - [[package]] name = "generic-array" version = "0.14.7" @@ -516,18 +310,6 @@ dependencies = [ "wasi", ] -[[package]] -name = "getrandom" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" -dependencies = [ - "cfg-if", - "libc", - "r-efi", - "wasip2", -] - [[package]] name = "globset" version = "0.4.18" @@ -552,27 +334,6 @@ dependencies = [ "walkdir", ] -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash 0.7.8", -] - -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - -[[package]] -name = "hashbrown" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" - [[package]] name = "heck" version = "0.5.0" @@ -628,33 +389,12 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "indexmap" -version = "2.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" -dependencies = [ - "equivalent", - "hashbrown 0.16.1", - "serde", - "serde_core", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.16" @@ -689,67 +429,12 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" -[[package]] -name = "lightningcss" -version = "1.0.0-alpha.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b407ca668368d1d5a86cea58ac82d9f9f9ca4bac1e9dce6f16f875f0f081a911" -dependencies = [ - "ahash 0.8.12", - "bitflags", - "const-str", - "cssparser", - "cssparser-color", - "dashmap", - "data-encoding", - "getrandom 0.3.4", - "indexmap", - "itertools", - "lazy_static", - "lightningcss-derive", - "parcel_selectors", - "parcel_sourcemap", - "pastey", - "pathdiff", - "rayon", - "serde", - "serde-content", - "smallvec", -] - -[[package]] -name = "lightningcss-derive" -version = "1.0.0-alpha.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12744d1279367caed41739ef094c325d53fb0ffcd4f9b84a368796f870252" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - [[package]] name = "log" version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - [[package]] name = "memchr" version = "2.7.6" @@ -777,55 +462,6 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" -[[package]] -name = "outref" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f222829ae9293e33a9f5e9f440c6760a3d450a64affe1846486b140db81c1f4" - -[[package]] -name = "parcel_selectors" -version = "0.28.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54fd03f1ad26cb6b3ec1b7414fa78a3bd639e7dbb421b1a60513c96ce886a196" -dependencies = [ - "bitflags", - "cssparser", - "log", - "phf", - "phf_codegen", - "precomputed-hash", - "rustc-hash", - "smallvec", -] - -[[package]] -name = "parcel_sourcemap" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "485b74d7218068b2b7c0e3ff12fbc61ae11d57cb5d8224f525bd304c6be05bbb" -dependencies = [ - "base64-simd", - "data-url", - "rkyv", - "serde", - "serde_json", - "vlq", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-link", -] - [[package]] name = "parse-zoneinfo" version = "0.3.1" @@ -835,18 +471,6 @@ dependencies = [ "regex", ] -[[package]] -name = "pastey" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" - -[[package]] -name = "pathdiff" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" - [[package]] name = "percent-encoding" version = "2.3.2" @@ -883,7 +507,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.111", + "syn", ] [[package]] @@ -902,7 +526,6 @@ version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ - "phf_macros", "phf_shared", ] @@ -926,19 +549,6 @@ dependencies = [ "rand", ] -[[package]] -name = "phf_macros" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" -dependencies = [ - "phf_generator", - "phf_shared", - "proc-macro2", - "quote", - "syn 2.0.111", -] - [[package]] name = "phf_shared" version = "0.11.3" @@ -957,12 +567,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - [[package]] name = "proc-macro2" version = "1.0.103" @@ -972,26 +576,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "ptr_meta" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" -dependencies = [ - "ptr_meta_derive", -] - -[[package]] -name = "ptr_meta_derive" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "pulldown-cmark" version = "0.13.0" @@ -1020,18 +604,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "r-efi" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" - -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - [[package]] name = "rand" version = "0.8.5" @@ -1059,36 +631,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.16", -] - -[[package]] -name = "rayon" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" -dependencies = [ - "crossbeam-deque", - "crossbeam-utils", -] - -[[package]] -name = "redox_syscall" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" -dependencies = [ - "bitflags", + "getrandom", ] [[package]] @@ -1108,7 +651,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn", ] [[package]] @@ -1140,50 +683,6 @@ version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" -[[package]] -name = "rend" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" -dependencies = [ - "bytecheck", -] - -[[package]] -name = "rkyv" -version = "0.7.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" -dependencies = [ - "bitvec", - "bytecheck", - "bytes", - "hashbrown 0.12.3", - "ptr_meta", - "rend", - "rkyv_derive", - "seahash", - "tinyvec", - "uuid", -] - -[[package]] -name = "rkyv_derive" -version = "0.7.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "rustc-hash" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" - [[package]] name = "rustversion" version = "1.0.22" @@ -1216,16 +715,11 @@ dependencies = [ name = "schemars-docgen" version = "0.1.0" dependencies = [ - "chrono", "clap", - "lightningcss", "pulldown-cmark", - "rayon", - "regex", "schemars", "serde", "serde_json", - "struct_iterable", "tera", "thiserror", ] @@ -1239,21 +733,9 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.111", + "syn", ] -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "seahash" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" - [[package]] name = "serde" version = "1.0.228" @@ -1264,15 +746,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde-content" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3753ca04f350fa92d00b6146a3555e63c55388c9ef2e11e09bce2ff1c0b509c6" -dependencies = [ - "serde", -] - [[package]] name = "serde_core" version = "1.0.228" @@ -1290,7 +763,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn", ] [[package]] @@ -1301,7 +774,7 @@ checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn", ] [[package]] @@ -1334,21 +807,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "simd-abstraction" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cadb29c57caadc51ff8346233b5cec1d240b68ce55cf1afc764818791876987" -dependencies = [ - "outref", -] - -[[package]] -name = "simdutf8" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" - [[package]] name = "siphasher" version = "1.0.1" @@ -1365,58 +823,12 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" -[[package]] -name = "struct_iterable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "849a064c6470a650b72e41fa6c057879b68f804d113af92900f27574828e7712" -dependencies = [ - "struct_iterable_derive", - "struct_iterable_internal", -] - -[[package]] -name = "struct_iterable_derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bb939ce88a43ea4e9d012f2f6b4cc789deb2db9d47bad697952a85d6978662c" -dependencies = [ - "erased-serde", - "proc-macro2", - "quote", - "struct_iterable_internal", - "syn 2.0.111", -] - -[[package]] -name = "struct_iterable_internal" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9426b2a0c03e6cc2ea8dbc0168dbbf943f88755e409fb91bcb8f6a268305f4a" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - [[package]] name = "syn" version = "2.0.111" @@ -1428,12 +840,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - [[package]] name = "tera" version = "1.20.1" @@ -1473,24 +879,9 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn", ] -[[package]] -name = "tinyvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "typenum" version = "1.19.0" @@ -1533,28 +924,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "uuid" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "version_check" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "vlq" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65dd7eed29412da847b0f78bcec0ac98588165988a8cfe41d4ea1d429f8ccfff" - [[package]] name = "walkdir" version = "2.5.0" @@ -1571,15 +946,6 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" -[[package]] -name = "wasip2" -version = "1.0.1+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" -dependencies = [ - "wit-bindgen", -] - [[package]] name = "wasm-bindgen" version = "0.2.106" @@ -1612,7 +978,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.111", + "syn", "wasm-bindgen-shared", ] @@ -1655,7 +1021,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn", ] [[package]] @@ -1666,7 +1032,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn", ] [[package]] @@ -1702,21 +1068,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "wit-bindgen" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - [[package]] name = "zerocopy" version = "0.8.31" @@ -1734,7 +1085,7 @@ checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 342f7868..f044866b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,14 +20,3 @@ tera = "1" pulldown-cmark = "0.13" clap = { version = "4", features = ["derive"] } thiserror = "2" -struct_iterable = "0.1" - -[build-dependencies] -lightningcss = "1.0.0-alpha.68" -struct_iterable = "0.1" -serde = { version = "1", features = ["derive"] } - -[dev-dependencies] -regex = "1" -rayon = "1" -chrono = "0.4" diff --git a/ENUMS.md b/ENUMS.md new file mode 100644 index 00000000..2f2a1da7 --- /dev/null +++ b/ENUMS.md @@ -0,0 +1,826 @@ +# Comprehensive Analysis: Rust Enum Representations in JSONSchema + +## Overview + +This document provides an exhaustive analysis of all the different ways Rust enums in the `komorebi-for-mac` project are represented in the generated schema files (`schema.json` and `schema.bar.json`). The project uses `schemars` with the `JsonSchema` derive macro for schema generation. + +--- + +## Pattern 1: Simple Unit Enums (String Constants) + +**Rust Pattern:** Enums where all variants have no associated data. + +**Serde Attributes:** None (default) or `#[serde(rename_all = "...")]` + +**JSONSchema Representation:** Uses `oneOf` with each variant as `{ "type": "string", "const": "VariantName" }` + +**Source Example:** `ApplicationIdentifier` in `komorebi/src/core/mod.rs` +```rust +#[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +pub enum ApplicationIdentifier { + /// Executable name + Exe, + /// Title + Title, + /// Path + Path, + /// App Bundle name + Name, +} +``` + +**Schema Output:** +```json +{ + "description": "Application identifier", + "oneOf": [ + { "description": "Executable name", "type": "string", "const": "Exe" }, + { "description": "Title", "type": "string", "const": "Title" }, + { "description": "Path", "type": "string", "const": "Path" }, + { "description": "App Bundle name", "type": "string", "const": "Name" } + ] +} +``` + +**Title/Discriminant Location:** +| Field | JSON Path | Description | +|-------|-----------|-------------| +| Variant Name | `oneOf[n].const` | The variant name as a string constant | +| Variant Description | `oneOf[n].description` | Doc comment from the variant | +| Enum Description | `description` | Doc comment from the enum | + +**Examples in schema.json:** +| Definition | Lines | +|------------|-------| +| `ApplicationIdentifier` | L570-594 | +| `Axis` | L622-641 | +| `CrossBoundaryBehaviour` | L2410-2424 | +| `FloatingLayerBehaviour` | L2476-2490 | +| `MatchingStrategy` | L2898-2952 | +| `MoveBehaviour` | L3050-3069 | +| `OperationBehaviour` | L3070-3084 | +| `Placement` | L3141-3160 | +| `PredefinedAspectRatio` | L3161-3180 | +| `ThemeVariant` | L3366-3380 | +| `WindowContainerBehaviour` | L3413-3427 | +| `WindowHidingPosition` | L3428-3442 | +| `Catppuccin` | L2237-2261 | +| `CatppuccinValue` | L2262-2396 | +| `Base16Value` | L2080-2164 | +| `Base16` | L642-1991 (270 theme variants) | + +**Examples in schema.bar.json:** +| Definition | Lines | +|------------|-------| +| `ApplicationsDisplayFormat` | L268-287 | +| `DisplayFormat` | L2241-2270 | +| `GroupingStyle` | L2441-2480 | +| `LabelPrefix` | L2958-2982 | + +--- + +## Pattern 2: Unit Enum with Default Value + +**Rust Pattern:** Unit enum with `#[schemars(extend("default" = Self::Variant))]` + +**JSONSchema Representation:** Same as Pattern 1, but with an additional `"default"` field at the enum level. + +**Source Example:** `DefaultLayout` in `komorebi/src/core/default_layout.rs` +```rust +#[derive(Clone, Copy, Debug, Serialize, Deserialize, Display, EnumString, ValueEnum, PartialEq)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +#[cfg_attr(feature = "schemars", schemars(extend("default" = Self::BSP)))] +pub enum DefaultLayout { + /// BSP Layout + BSP, + /// Columns Layout + Columns, + // ... more variants +} +``` + +**Schema Output:** +```json +{ + "description": "A predefined komorebi layout", + "default": "BSP", + "oneOf": [ + { "description": "BSP Layout", "type": "string", "const": "BSP" }, + { "description": "Columns Layout", "type": "string", "const": "Columns" }, + ... + ] +} +``` + +**Title/Discriminant Location:** +| Field | JSON Path | Description | +|-------|-----------|-------------| +| Variant Name | `oneOf[n].const` | The variant name as a string constant | +| Default Value | `default` | The default variant name (at enum root level) | +| Variant Description | `oneOf[n].description` | Doc comment from the variant | + +**Examples:** +| Schema | Definition | Lines | +|--------|------------|-------| +| schema.json | `DefaultLayout` | L2425-2475 | +| schema.bar.json | `DefaultLayout` | L2190-2240 | + +--- + +## Pattern 3: Mixed Enum (Unit Variants + Newtype Variants) + +**Rust Pattern:** Enum with mostly unit variants plus one or more tuple/newtype variants containing data. Uses default external tagging. + +**JSONSchema Representation:** Uses `oneOf` where: +- Unit variants become `{ "type": "string", "const": "Name" }` +- Newtype variants become objects with the variant name as a property key + +**Source Example:** `DateFormat` in `komorebi-bar/src/widgets/date.rs` +```rust +#[derive(Clone, Debug, Serialize, Deserialize)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +pub enum DateFormat { + /// Month/Date/Year format (09/08/24) + MonthDateYear, + /// Year-Month-Date format (2024-09-08) + YearMonthDate, + /// Custom format + #[cfg_attr(feature = "schemars", schemars(title = "Custom"))] + Custom(String), + /// Custom format with modifiers + #[cfg_attr(feature = "schemars", schemars(title = "CustomModifiers"))] + CustomModifiers(CustomModifiers), +} +``` + +**Schema Output:** +```json +{ + "description": "Date widget format", + "oneOf": [ + { "description": "Month/Date/Year format", "type": "string", "const": "MonthDateYear" }, + { "description": "Year-Month-Date format", "type": "string", "const": "YearMonthDate" }, + { + "title": "Custom", + "description": "Custom format", + "type": "object", + "properties": { + "Custom": { "type": "string" } + }, + "additionalProperties": false, + "required": ["Custom"] + }, + { + "title": "CustomModifiers", + "type": "object", + "properties": { + "CustomModifiers": { "$ref": "#/$defs/CustomModifiers" } + }, + "additionalProperties": false, + "required": ["CustomModifiers"] + } + ] +} +``` + +**Title/Discriminant Location:** +| Variant Type | Field | JSON Path | Description | +|--------------|-------|-----------|-------------| +| Unit | Variant Name | `oneOf[n].const` | The variant name as a string constant | +| Unit | Description | `oneOf[n].description` | Doc comment from the variant | +| Newtype | Title | `oneOf[n].title` | Variant name (from `#[schemars(title = "...")]`) | +| Newtype | Property Key | `oneOf[n].properties.` | Variant name as object property key | +| Newtype | Required | `oneOf[n].required[0]` | Variant name in required array | + +**Examples in schema.bar.json:** +| Definition | Lines | +|------------|-------| +| `DateFormat` | L2137-2189 | +| `TimeFormat` | L3442-3490 | +| `KomorebiLayout` | L2794-2832 | + +**Examples in schema.json:** +| Definition | Lines | Notes | +|------------|-------|-------| +| `AnimationStyle` | L312-505 | 31 unit variants + `CubicBezier(f64,f64,f64,f64)` - **Note: Has custom Serialize/Deserialize that serializes CubicBezier as bare array, but schema shows wrapped object** | + +--- + +## Pattern 4: Untagged Enum (anyOf) + +**Rust Pattern:** Enum with `#[serde(untagged)]` attribute. + +**JSONSchema Representation:** Uses `anyOf` (not `oneOf`) with each variant's type directly, without wrapper objects or discriminator fields. + +### Subpattern 4a: Untagged with Primitives + +**Source Example:** `MonitorConfigOrIndex` in `komorebi-bar/src/config.rs` +```rust +#[derive(Clone, Debug, Serialize, Deserialize)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +#[serde(untagged)] +pub enum MonitorConfigOrIndex { + /// The monitor index + Index(usize), + /// The full monitor config + MonitorConfig(MonitorConfig), +} +``` + +**Schema Output:** +```json +{ + "description": "Monitor configuration or monitor index", + "anyOf": [ + { "description": "The monitor index", "type": "integer", "format": "uint", "minimum": 0 }, + { "description": "The full monitor config", "$ref": "#/$defs/MonitorConfig" } + ] +} +``` + +### Subpattern 4b: Untagged with Multiple Struct Refs + +**Source Example:** `SpacingKind` in `komorebi-bar/src/config.rs` +```rust +#[derive(Clone, Debug, Serialize, Deserialize)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +#[serde(untagged)] +// WARNING: Order matters! Grouped must come last +pub enum SpacingKind { + /// Spacing applied to all sides + All(f32), + /// Individual spacing + Individual(IndividualSpacingConfig), + /// Grouped spacing + Grouped(GroupedSpacingConfig), +} +``` + +**Schema Output:** +```json +{ + "description": "Spacing kind", + "anyOf": [ + { "description": "Spacing applied to all sides", "type": "number", "format": "float" }, + { "description": "Individual spacing", "$ref": "#/$defs/IndividualSpacingConfig" }, + { "description": "Grouped spacing", "$ref": "#/$defs/GroupedSpacingConfig" } + ] +} +``` + +### Subpattern 4c: Untagged with Two $refs + +**Source Example:** `Colour` in `komorebi/src/core/colour.rs` +```rust +#[derive(Clone, Debug, Serialize, Deserialize)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +#[serde(untagged)] +pub enum Colour { + /// RGB representation + Rgb(Rgb), + /// Hex representation + Hex(Hex), +} +``` + +**Schema Output:** +```json +{ + "description": "Colour representation", + "anyOf": [ + { "description": "Colour represented as RGB", "$ref": "#/$defs/Rgb" }, + { "description": "Colour represented as Hex", "$ref": "#/$defs/Hex" } + ] +} +``` + +### Subpattern 4d: Untagged with Single vs Array + +**Source Example:** `MatchingRule` in `komorebi/src/core/config_generation.rs` +```rust +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +#[serde(untagged)] +pub enum MatchingRule { + /// Simple matching rule + Simple(IdWithIdentifier), + /// Composite matching rule + Composite(Vec), +} +``` + +**Schema Output:** +```json +{ + "description": "Rule for matching applications", + "anyOf": [ + { "description": "Simple matching rule", "$ref": "#/$defs/IdWithIdentifier" }, + { "description": "Composite matching rule", "type": "array", "items": { "$ref": "#/$defs/IdWithIdentifier" } } + ] +} +``` + +### Subpattern 4e: Untagged with Tuple + +**Source Example:** `GroupedSpacingOptions` in `komorebi-bar/src/config.rs` +```rust +#[derive(Clone, Debug, Serialize, Deserialize)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +#[serde(untagged)] +pub enum GroupedSpacingOptions { + /// Symmetrical spacing + Symmetrical(f32), + /// Split spacing (top/left, bottom/right) + Split(f32, f32), +} +``` + +**Schema Output:** +```json +{ + "description": "Grouped spacing options", + "anyOf": [ + { "description": "Symmetrical spacing", "type": "number", "format": "float" }, + { + "description": "Split spacing", + "type": "array", + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { "type": "number", "format": "float" }, + { "type": "number", "format": "float" } + ] + } + ] +} +``` + +**Title/Discriminant Location:** +| Field | JSON Path | Description | +|-------|-----------|-------------| +| Variant Description | `anyOf[n].description` | Doc comment from the variant | +| Variant Title (optional) | `anyOf[n].title` | Title if `#[schemars(title = "...")]` is used | +| **No discriminant** | N/A | Untagged enums have no discriminant field - they rely on type matching | + +**Note:** Untagged enums use `anyOf` (not `oneOf`) and do not have explicit discriminant values. The JSON parser tries each variant in order until one matches the input structure. + +**All Untagged Enum Examples:** +| Schema | Definition | Lines | Subpattern | +|--------|------------|-------|------------| +| schema.json | `Colour` | L2397-2409 | 4c | +| schema.json | `MatchingRule` | L2882-2897 | 4d | +| schema.json | `AspectRatio` | L595-621 | 4a (ref + tuple) | +| schema.json | `AppSpecificConfigurationPath` | L554-569 | 4d (ref + array) | +| schema.bar.json | `MonitorConfigOrIndex` | L3053-3067 | 4a | +| schema.bar.json | `SpacingKind` | L3310-3327 | 4b | +| schema.bar.json | `GroupedSpacingOptions` | L2312-2337 | 4e | +| schema.bar.json | `RoundingConfig` | L3290-3309 | 4e | + +--- + +## Pattern 5: Internally Tagged Enum (Struct Variants with Discriminator) + +**Rust Pattern:** Enum with `#[serde(tag = "field_name")]` where variants have named fields (struct variants). + +**JSONSchema Representation:** Uses `oneOf` where each variant is an object with: +- A discriminator field with `{ "type": "string", "const": "VariantName" }` +- All other fields from the struct variant +- The discriminator field in `required` array + +**Source Example:** `KomorebiTheme` in `komorebi/src/static_config.rs` +```rust +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +#[serde(tag = "palette")] +pub enum KomorebiTheme { + /// A theme from catppuccin-egui + #[cfg_attr(feature = "schemars", schemars(title = "Catppuccin"))] + Catppuccin { + name: komorebi_themes::Catppuccin, + #[serde(skip_serializing_if = "Option::is_none")] + single_border: Option, + // ... more fields + }, + /// A theme from base16-egui-themes + #[cfg_attr(feature = "schemars", schemars(title = "Base16"))] + Base16 { + name: komorebi_themes::Base16, + // ... fields + }, + /// A custom Base16 theme + #[cfg_attr(feature = "schemars", schemars(title = "Custom"))] + Custom { + colours: Base16ColourPalette, + // ... fields + }, +} +``` + +**Schema Output:** +```json +{ + "description": "Komorebi theme", + "oneOf": [ + { + "title": "Catppuccin", + "description": "A theme from catppuccin-egui", + "type": "object", + "properties": { + "palette": { "type": "string", "const": "Catppuccin" }, + "name": { "$ref": "#/$defs/Catppuccin" }, + "single_border": { "anyOf": [{ "$ref": "#/$defs/CatppuccinValue" }, { "type": "null" }], "default": "Blue" } + }, + "required": ["palette", "name"] + }, + { + "title": "Base16", + "type": "object", + "properties": { + "palette": { "type": "string", "const": "Base16" }, + "name": { "$ref": "#/$defs/Base16" } + }, + "required": ["palette", "name"] + }, + { + "title": "Custom", + "type": "object", + "properties": { + "palette": { "type": "string", "const": "Custom" }, + "colours": { "$ref": "#/$defs/Base16ColourPalette" } + }, + "required": ["palette", "colours"] + } + ] +} +``` + +**Title/Discriminant Location:** +| Field | JSON Path | Description | +|-------|-----------|-------------| +| Variant Title | `oneOf[n].title` | Variant name (from `#[schemars(title = "...")]`) | +| **Discriminant Field** | `oneOf[n].properties.` | The tag field (e.g., `palette`) as a property | +| **Discriminant Value** | `oneOf[n].properties..const` | The variant name as const value | +| Required Fields | `oneOf[n].required` | Contains the tag field name | + +**Note:** The discriminant field name comes from `#[serde(tag = "...")]`. In this case, `palette` is the tag field, and each variant has `properties.palette.const` set to its variant name. + +**Examples:** +| Schema | Definition | Discriminator | Lines | +|--------|------------|---------------|-------| +| schema.json | `KomorebiTheme` | `palette` | L2540-2853 | +| schema.bar.json | `KomobarTheme` | `palette` | L2518-2669 | + +--- + +## Pattern 6: Internally Tagged Enum with Flattened Newtype Variants + +**Rust Pattern:** Enum with `#[serde(tag = "kind")]` where some variants wrap a struct (newtype pattern). The wrapped struct's fields get flattened. + +**JSONSchema Representation:** Uses `oneOf` where: +- Each variant has a discriminator field (`kind`) +- Variants that wrap structs include `$ref` at the same level to merge properties + +**Source Example:** `Grouping` in `komorebi-bar/src/render.rs` +```rust +#[derive(Copy, Clone, Debug, Serialize, Deserialize)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +#[serde(tag = "kind")] +pub enum Grouping { + /// No grouping + #[cfg_attr(feature = "schemars", schemars(title = "None"))] + None, + /// Grouped as a whole + #[cfg_attr(feature = "schemars", schemars(title = "Bar"))] + Bar(GroupingConfig), + /// Grouped by alignment + #[cfg_attr(feature = "schemars", schemars(title = "Alignment"))] + Alignment(GroupingConfig), + /// Grouped individually + #[cfg_attr(feature = "schemars", schemars(title = "Widget"))] + Widget(GroupingConfig), +} +``` + +**Schema Output:** +```json +{ + "description": "Grouping", + "oneOf": [ + { + "title": "None", + "description": "No grouping is applied", + "type": "object", + "properties": { + "kind": { "type": "string", "const": "None" } + }, + "required": ["kind"] + }, + { + "title": "Bar", + "description": "Widgets are grouped as a whole", + "type": "object", + "properties": { + "kind": { "type": "string", "const": "Bar" } + }, + "$ref": "#/$defs/GroupingConfig", + "required": ["kind"] + } + ] +} +``` + +**Title/Discriminant Location:** +| Field | JSON Path | Description | +|-------|-----------|-------------| +| Variant Title | `oneOf[n].title` | Variant name (from `#[schemars(title = "...")]`) | +| **Discriminant Field** | `oneOf[n].properties.` | The tag field (e.g., `kind`) as a property | +| **Discriminant Value** | `oneOf[n].properties..const` | The variant name as const value | +| Flattened Properties | `oneOf[n].$ref` | Reference to merged struct (only for newtype variants) | +| Required Fields | `oneOf[n].required` | Contains the tag field name | + +**Note:** Similar to Pattern 5, but newtype variants include a `$ref` at the variant level that merges in additional properties from the wrapped struct. The `$ref` appears alongside `properties` and `required`. + +**Examples:** +| Schema | Definition | Discriminator | Lines | +|--------|------------|---------------|-------| +| schema.bar.json | `Grouping` | `kind` | L2338-2401 | + +--- + +## Pattern 7: Externally Tagged Enum (Newtype Variants Only) + +**Rust Pattern:** Enum with only newtype variants (no unit variants), using default external tagging. + +**JSONSchema Representation:** Uses `oneOf` where each variant is an object with: +- The variant name as a property key +- The wrapped type as the property value (usually a `$ref`) +- `additionalProperties: false` +- The variant name in `required` array + +**Source Example:** `WidgetConfig` in `komorebi-bar/src/widgets/widget.rs` +```rust +#[derive(Clone, Debug, Serialize, Deserialize)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +pub enum WidgetConfig { + /// Applications widget + #[cfg_attr(feature = "schemars", schemars(title = "Applications"))] + Applications(ApplicationsConfig), + /// Battery widget + #[cfg_attr(feature = "schemars", schemars(title = "Battery"))] + Battery(BatteryConfig), + // ... 8 more variants +} +``` + +**Schema Output:** +```json +{ + "description": "Widget configuration", + "oneOf": [ + { + "title": "Applications", + "description": "Applications widget configuration", + "type": "object", + "properties": { + "Applications": { "$ref": "#/$defs/ApplicationsConfig" } + }, + "additionalProperties": false, + "required": ["Applications"] + }, + { + "title": "Battery", + "type": "object", + "properties": { + "Battery": { "$ref": "#/$defs/BatteryConfig" } + }, + "additionalProperties": false, + "required": ["Battery"] + } + ] +} +``` + +**Title/Discriminant Location:** +| Field | JSON Path | Description | +|-------|-----------|-------------| +| Variant Title | `oneOf[n].title` | Variant name (from `#[schemars(title = "...")]`) | +| **Discriminant (Property Key)** | `oneOf[n].properties.` | Variant name is the property key itself | +| **Discriminant (Required)** | `oneOf[n].required[0]` | Variant name in required array | +| Wrapped Type | `oneOf[n].properties..$ref` | Reference to the wrapped struct | + +**Note:** In externally tagged enums, the variant name serves as both the property key and the discriminant. There is no separate `const` field - the presence of the property key identifies the variant. + +**Examples:** +| Schema | Definition | Lines | +|--------|------------|-------| +| schema.bar.json | `WidgetConfig` | L3525-3669 | + +--- + +## Pattern 8: Adjacently Tagged Enum + +**Rust Pattern:** Enum with `#[serde(tag = "type", content = "content")]` - tag and content in separate fields. + +**JSONSchema Representation:** This pattern is used for internal message types but may not appear in the public config schemas. + +**Source Example:** `SocketMessage` in `komorebi/src/core/mod.rs` +```rust +#[serde_with::serde_as] +#[derive(Clone, Debug, Serialize, Deserialize, Display)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +#[serde(tag = "type", content = "content")] +pub enum SocketMessage { + FocusWindow(OperationDirection), + MoveWindow(OperationDirection), + CancelPreselect, + // ... many more variants +} +``` + +**Title/Discriminant Location:** +| Field | JSON Path | Description | +|-------|-----------|-------------| +| **Tag Field** | `oneOf[n].properties.` | The tag field (e.g., `type`) | +| **Tag Value** | `oneOf[n].properties..const` | The variant name as const value | +| **Content Field** | `oneOf[n].properties.` | The content field (e.g., `content`) | +| Content Value | `oneOf[n].properties..*` | The variant's data | + +**Note:** `SocketMessage`, `WindowManagerEvent`, and `SystemNotification` use this pattern but are primarily for IPC, not user configuration. They may not appear in the public schema files. + +--- + +## Pattern 9: Untagged Hybrid Enum (Unit Variants + $ref Fallback) + +**Rust Pattern:** Macro-generated enum using `extend_enum!` with `#[serde(untagged)]` on the fallback variant. + +**Source Example:** `WorkspacesDisplayFormat` in `komorebi-bar/src/config.rs` +```rust +extend_enum!( + DisplayFormat, WorkspacesDisplayFormat, { + /// Show all icons only + AllIcons, + /// Show both all icons and text + AllIconsAndText, + /// Show all icons and text for the selected element + AllIconsAndTextOnSelected, +}); +``` + +Which expands to include an `#[serde(untagged)] Existing(DisplayFormat)` variant. + +**Schema Output:** +```json +{ + "description": "Workspaces display format", + "anyOf": [ + { "description": "Show all icons only", "type": "string", "const": "AllIcons" }, + { "description": "Show both all icons and text", "type": "string", "const": "AllIconsAndText" }, + { "description": "Show all icons and text for the selected element", "type": "string", "const": "AllIconsAndTextOnSelected" }, + { "$ref": "#/$defs/DisplayFormat" } + ] +} +``` + +**Title/Discriminant Location:** +| Variant Type | Field | JSON Path | Description | +|--------------|-------|-----------|-------------| +| Unit | Variant Name | `anyOf[n].const` | The variant name as a string constant | +| Unit | Description | `anyOf[n].description` | Doc comment from the variant | +| Fallback | Reference | `anyOf[n].$ref` | Reference to the base enum for additional variants | + +**Note:** This hybrid pattern combines explicit unit variants with a `$ref` fallback to another enum. The `$ref` variant has no `const` - it delegates to the referenced enum's schema. + +**Examples:** +| Schema | Definition | Lines | +|--------|------------|-------| +| schema.bar.json | `WorkspacesDisplayFormat` | L3670-3692 | + +--- + +## Pattern 10: Generic Enum Instantiations + +**Rust Pattern:** Generic enum like `PerAnimationPrefixConfig` with `#[serde(untagged)]` instantiated with different type parameters. + +**JSONSchema Representation:** Creates separate definitions for each instantiation, with numbered suffixes. + +**Source Example:** (likely in `komorebi/src/animation/mod.rs`) +```rust +#[derive(Clone, Debug, Serialize, Deserialize)] +#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] +#[serde(untagged)] +pub enum PerAnimationPrefixConfig { + /// Prefixed config + Prefix(HashMap), + /// Global config + Global(T), +} +``` + +**Schema Output (for bool):** +```json +{ + "description": "Animation configuration", + "anyOf": [ + { + "description": "Prefixed config", + "type": "object", + "additionalProperties": { "type": "boolean" } + }, + { + "description": "Global config", + "type": "boolean" + } + ] +} +``` + +**Title/Discriminant Location:** +| Field | JSON Path | Description | +|-------|-----------|-------------| +| Variant Description | `anyOf[n].description` | Doc comment from the variant | +| **No discriminant** | N/A | Untagged - relies on type matching | +| Definition Name | `$defs/` or `$defs/` | Numbered suffix for each instantiation | + +**Note:** Each generic instantiation creates a separate definition. The first uses the base name, subsequent ones get numeric suffixes (e.g., `PerAnimationPrefixConfig2`, `PerAnimationPrefixConfig3`). + +**Examples in schema.json:** +| Definition | Type Parameter | Lines | +|------------|---------------|-------| +| `PerAnimationPrefixConfig` | `bool` | L3089-3104 | +| `PerAnimationPrefixConfig2` | `u64` | L3105-3124 | +| `PerAnimationPrefixConfig3` | `AnimationStyle` | L3125-3140 | + +--- + +## Summary Table + +| Pattern | Serde Attribute | JSONSchema Keyword | Discriminant Location | +|---------|-----------------|-------------------|----------------------| +| 1. Simple Unit | (none) | `oneOf` | `oneOf[n].const` | +| 2. Unit + Default | `#[schemars(extend)]` | `oneOf` + `default` | `oneOf[n].const` + root `default` | +| 3. Mixed (Unit + Newtype) | (none) | `oneOf` | Units: `oneOf[n].const`; Newtypes: `oneOf[n].properties.` + `oneOf[n].required[0]` | +| 4. Untagged | `#[serde(untagged)]` | `anyOf` | None (type-based matching) | +| 5. Internally Tagged | `#[serde(tag = "...")]` | `oneOf` | `oneOf[n].properties..const` | +| 6. Internally Tagged + Newtype | `#[serde(tag = "...")]` | `oneOf` with `$ref` | `oneOf[n].properties..const` + `oneOf[n].$ref` | +| 7. Externally Tagged (Newtype) | (none/default) | `oneOf` | `oneOf[n].properties.` + `oneOf[n].required[0]` | +| 8. Adjacently Tagged | `#[serde(tag, content)]` | `oneOf` | `oneOf[n].properties..const` + `oneOf[n].properties.` | +| 9. Untagged Hybrid | `#[serde(untagged)]` on fallback | `anyOf` | Units: `anyOf[n].const`; Fallback: `anyOf[n].$ref` | +| 10. Generic | `#[serde(untagged)]` | `anyOf` | None; Definition name has numeric suffix | + +### Title Location by Pattern + +| Pattern | Title Location | Notes | +|---------|---------------|-------| +| 1. Simple Unit | No `title` field | Variant name is in `const` | +| 2. Unit + Default | No `title` field | Variant name is in `const` | +| 3. Mixed | `oneOf[n].title` (newtypes only) | From `#[schemars(title = "...")]` | +| 4. Untagged | `anyOf[n].title` (optional) | Rarely used | +| 5. Internally Tagged | `oneOf[n].title` | From `#[schemars(title = "...")]` | +| 6. Internally Tagged + Newtype | `oneOf[n].title` | From `#[schemars(title = "...")]` | +| 7. Externally Tagged | `oneOf[n].title` | From `#[schemars(title = "...")]` | +| 8. Adjacently Tagged | `oneOf[n].title` | From `#[schemars(title = "...")]` | +| 9. Untagged Hybrid | No `title` for units | Unit names in `const`, fallback is `$ref` | +| 10. Generic | No `title` | Definition name identifies the instantiation | + +--- + +## Key Observations + +1. **`oneOf` vs `anyOf`**: Tagged enums use `oneOf` (exactly one must match); untagged enums use `anyOf` (first match wins). + +2. **Unit variants**: Always represented as `{ "type": "string", "const": "VariantName" }`. + +3. **Newtype variants with default tagging**: Become objects where the variant name is a property key containing the data. + +4. **Struct variants with internal tagging**: The tag field appears as a regular property with a `const` value. + +5. **Generic type monomorphization**: Each instantiation gets a separate schema definition with numeric suffixes. + +6. **Descriptions preserved**: Both enum-level and variant-level doc comments appear in the schema. + +7. **`#[schemars(title = "...")]`**: Used to control the `title` field in schema output for variants. + +8. **Custom Serialize/Deserialize**: When enums have custom implementations (like `AnimationStyle`), the schema may not match the actual serialization format exactly. + +9. **Variant ordering in untagged enums**: Order matters! See `SpacingKind` warning comment. + +10. **Optional fields in struct variants**: Use `anyOf: [{ $ref }, { type: null }]` pattern with `default` values. + +--- + +## Source Files Reference + +| File | Key Enums | +|------|-----------| +| `komorebi/src/core/mod.rs` | `ApplicationIdentifier`, `SocketMessage`, `OperationBehaviour`, `WindowContainerBehaviour`, `FloatingLayerBehaviour`, `Placement`, `MoveBehaviour`, `CrossBoundaryBehaviour` | +| `komorebi/src/core/config_generation.rs` | `MatchingRule`, `MatchingStrategy`, `ApplicationOptions` | +| `komorebi/src/core/default_layout.rs` | `DefaultLayout` | +| `komorebi/src/core/animation.rs` | `AnimationStyle` | +| `komorebi/src/static_config.rs` | `KomorebiTheme` | +| `komorebi/src/animation/mod.rs` | `PerAnimationPrefixConfig` | +| `komorebi-bar/src/config.rs` | `MonitorConfigOrIndex`, `SpacingKind`, `GroupedSpacingOptions`, `KomobarTheme`, `WorkspacesDisplayFormat` | +| `komorebi-bar/src/render.rs` | `Grouping`, `GroupingStyle`, `RoundingConfig` | +| `komorebi-bar/src/widgets/widget.rs` | `WidgetConfig` | +| `komorebi-bar/src/widgets/date.rs` | `DateFormat` | +| `komorebi-bar/src/widgets/time.rs` | `TimeFormat` | diff --git a/build.rs b/build.rs deleted file mode 100644 index 6d2310b9..00000000 --- a/build.rs +++ /dev/null @@ -1,95 +0,0 @@ -#[path = "src/identifiers.rs"] -mod identifiers; - -use identifiers::CSS; -use identifiers::TYPE_CLASSES; -use lightningcss::rules::CssRule; -use lightningcss::selector::Component; -use lightningcss::stylesheet::ParserOptions; -use lightningcss::stylesheet::StyleSheet; -use std::collections::HashSet; -use std::fs; -use struct_iterable::Iterable; - -fn main() { - println!("cargo:rerun-if-changed=src/templates/style.css"); - println!("cargo:rerun-if-changed=src/identifiers.rs"); - - let css_content = - fs::read_to_string("src/templates/style.css").expect("Failed to read style.css"); - - // Parse CSS and extract class names - let css_classes = extract_css_classes(&css_content); - - // Collect all defined classes using struct_iterable's automatic iteration - let mut defined_classes: HashSet<&str> = HashSet::new(); - - // Iterate over CssClasses fields - automatically includes ALL fields - for (_field_name, field_value) in CSS.iter() { - if let Some(class) = field_value.downcast_ref::<&str>() { - defined_classes.insert(*class); - } - } - - // Iterate over TypeClasses fields - automatically includes ALL fields - for (_field_name, field_value) in TYPE_CLASSES.iter() { - if let Some(class) = field_value.downcast_ref::<&str>() { - defined_classes.insert(*class); - } - } - - // Dynamic classes to skip (generated at runtime) - let dynamic_prefixes = ["depth-"]; - - // Check for CSS classes not defined in identifiers.rs - let undefined: Vec<&String> = css_classes - .iter() - .filter(|c| !defined_classes.contains(c.as_str())) - .filter(|c| !dynamic_prefixes.iter().any(|p| c.starts_with(p))) - .collect(); - - if !undefined.is_empty() { - let undefined_list: Vec<&str> = undefined.iter().map(|s| s.as_str()).collect(); - panic!( - "CSS classes in style.css not defined in identifiers.rs:\n {}", - undefined_list.join("\n ") - ); - } - - // Warn about defined classes not used in CSS - for class in &defined_classes { - if !css_classes.contains(*class) { - println!("cargo:warning=Class '{}' defined but not styled", class); - } - } -} - -fn extract_css_classes(css: &str) -> HashSet { - let mut classes = HashSet::new(); - - let stylesheet = StyleSheet::parse(css, ParserOptions::default()).expect("Failed to parse CSS"); - - fn collect_from_rules(rules: &[CssRule], classes: &mut HashSet) { - for rule in rules { - match rule { - CssRule::Style(style_rule) => { - for selector in style_rule.selectors.0.iter() { - for component in selector.iter_raw_match_order() { - if let Component::Class(class_name) = component { - classes.insert(class_name.0.to_string()); - } - } - } - collect_from_rules(&style_rule.rules.0, classes); - } - CssRule::Media(media_rule) => { - collect_from_rules(&media_rule.rules.0, classes); - } - _ => {} - } - } - } - - collect_from_rules(&stylesheet.rules.0, &mut classes); - classes -} diff --git a/src/generator.rs b/src/generator.rs deleted file mode 100644 index 4f61e733..00000000 --- a/src/generator.rs +++ /dev/null @@ -1,1827 +0,0 @@ -//! HTML generation using Tera templates - -use crate::Error; -use crate::Options; -use crate::identifiers::CSS; -use crate::identifiers::IDS; -use crate::identifiers::TYPE_CLASSES; -use crate::prepare::NavigationData; -use crate::prepare::build_navigation; -use crate::prepare::embed_usages_in_defs; -use crate::prepare::prepare_for_template; -use crate::prepare::render_markdown; -use crate::prepare::strip_markdown; -use schemars::Schema; -use serde_json::Value; -use tera::Context; -use tera::Tera; - -/// HTML documentation generator -pub struct Generator { - tera: Tera, -} - -impl Generator { - /// Create a new generator with embedded templates - pub fn new() -> Result { - let mut tera = Tera::default(); - - // Add templates from embedded strings - // Order matters: macros and style must be added before base.html which imports them - tera.add_raw_template("style.css", include_str!("templates/style.css"))?; - tera.add_raw_template("macros.html", include_str!("templates/macros.html"))?; - tera.add_raw_template("base.html", include_str!("templates/base.html"))?; - - Ok(Self { tera }) - } - - /// Generate HTML documentation from a schema - pub fn generate(&self, schema: &Schema, options: &Options) -> Result { - // Prepare the schema for template rendering - let mut prepared_schema = prepare_for_template(schema.as_value()); - - // Build navigation data from the prepared schema (includes _display_name for wrapper types) - let navigation = build_navigation(&prepared_schema); - - // Embed usages directly into $defs to avoid Tera lookup issues with special characters - embed_usages_in_defs(&mut prepared_schema, &navigation.usages); - - // Build the template context - let context = self.build_context(&prepared_schema, &navigation, options)?; - - // Render the template - let html = self.tera.render("base.html", &context)?; - - Ok(html) - } - - /// Build the Tera context from schema and options - fn build_context( - &self, - schema: &Value, - navigation: &NavigationData, - options: &Options, - ) -> Result { - let mut context = Context::new(); - - // Title: use override, then description, then schema title - let title = options - .title_override - .clone() - .or_else(|| { - schema - .get("description") - .and_then(|v| v.as_str()) - .map(String::from) - }) - .or_else(|| { - schema - .get("title") - .and_then(|v| v.as_str()) - .map(String::from) - }) - .unwrap_or_else(|| "Schema Documentation".to_string()); - // Render title as markdown HTML (for h1 display) - let title_html = render_markdown(&title); - // Strip markdown for plain text title (for HTML tag) - let title_plain = strip_markdown(&title); - context.insert("title", &title_plain); - context.insert("title_html", &title_html); - - // The full schema for property rendering - context.insert("schema", schema); - - // Navigation data for sidebar - context.insert("navigation", navigation); - - // Search index as JSON for the JavaScript - context.insert("search_index", &navigation.search_index); - - // Type usages for "Usages" section in type definitions - context.insert("usages", &navigation.usages); - - // Display names for wrapper types (type_name -> display_name) - context.insert("display_names", &navigation.display_names); - - // Build required set for the root schema - let required_set: Vec<String> = schema - .get("required") - .and_then(|v| v.as_array()) - .map(|arr| { - arr.iter() - .filter_map(|v| v.as_str().map(String::from)) - .collect() - }) - .unwrap_or_default(); - context.insert("required_set", &required_set); - - // Add CSS classes and HTML IDs from the single source of truth - context.insert("ids", &IDS); - context.insert("css", &CSS); - context.insert("type_classes", &TYPE_CLASSES); - - Ok(context) - } -} - -impl Default for Generator { - fn default() -> Self { - Self::new().expect("Failed to create default generator") - } -} - -#[cfg(test)] -mod tests { - use super::*; - use serde_json::json; - - fn make_schema(value: Value) -> Schema { - serde_json::from_value(value).unwrap() - } - - #[test] - fn test_generator_new() { - let generator = Generator::new(); - assert!(generator.is_ok()); - } - - #[test] - fn test_generate_simple_schema() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "TestConfig", - "description": "A test configuration", - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "The name" - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options); - assert!(html.is_ok()); - - let html = html.unwrap(); - // Description is now used as the page title - assert!(html.contains("A test configuration")); - assert!(html.contains("name")); - assert!(html.contains("The name")); - } - - #[test] - fn test_generate_with_title_override() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "OriginalTitle", - "type": "object" - })); - - let options = Options { - title_override: Some("Custom Title".to_string()), - }; - - let html = generator.generate(&schema, &options).unwrap(); - assert!(html.contains("Custom Title")); - assert!(!html.contains("<title>OriginalTitle")); - } - - #[test] - fn test_generate_with_definitions() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "$defs": { - "MyType": { - "type": "string", - "description": "A custom type" - } - }, - "properties": { - "field": { - "$ref": "#/$defs/MyType" - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - assert!(html.contains("MyType")); - assert!(html.contains("A custom type")); - assert!(html.contains("href=\"#mytype\"")); - } - - #[test] - fn test_generate_with_enum() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "status": { - "type": "string", - "enum": ["active", "inactive", "pending"] - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - assert!(html.contains("active")); - assert!(html.contains("inactive")); - assert!(html.contains("pending")); - } - - #[test] - fn test_generate_with_anyof() { - let generator = Generator::new().unwrap(); - // Use 3 variants to ensure it's not treated as Option - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "value": { - "anyOf": [ - {"type": "string"}, - {"type": "number"}, - {"type": "boolean"} - ] - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // anyOf now renders as "enum" badge - assert!(html.contains(">enum<"), "Should show enum badge"); - assert!(html.contains("string")); - assert!(html.contains("number")); - assert!(html.contains("boolean")); - } - - #[test] - fn test_generate_with_markdown_description() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "description": "This is **bold** and `code`", - "type": "object" - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Description is now used as the page title (markdown stripped for ) - assert!( - html.contains("This is bold and code"), - "Description should be used as title with markdown stripped" - ); - // The h1 should have rendered markdown - assert!( - html.contains("<strong>bold</strong>"), - "h1 should have rendered markdown" - ); - } - - #[test] - fn test_generate_responsive_html() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object" - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Check for responsive viewport meta tag - assert!(html.contains("viewport")); - assert!(html.contains("width=device-width")); - - // Check for responsive CSS - assert!(html.contains("@media")); - assert!(html.contains("min-width: 768px")); - } - - #[test] - fn test_generate_dark_mode_css() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object" - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Check for dark mode media query - assert!(html.contains("prefers-color-scheme: dark")); - } - - // Regression test: macro parameter 'schema' was conflicting with global context 'schema' - // This caused infinite recursion when rendering properties with enum values - #[test] - fn test_enum_property_no_infinite_recursion() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "status": { - "type": "string", - "enum": ["active", "inactive", "pending"], - "description": "The status of the item" - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Should contain enum values, not infinite nesting - assert!(html.contains("active")); - assert!(html.contains("inactive")); - assert!(html.contains("pending")); - - // Should NOT have deeply nested duplicate property names (sign of infinite recursion) - // Count occurrences of "status" in property names - should be limited - let status_count = html.matches("data-search-name=\"status\"").count(); - assert!( - status_count <= 2, - "Expected at most 2 occurrences of status property, found {}", - status_count - ); - } - - // Regression test: anyOf properties should render correctly - // Updated: string + null is now recognized as Option<T> pattern - #[test] - fn test_anyof_property_renders_variants() { - let generator = Generator::new().unwrap(); - // Use string + number to test regular anyOf (not Option<T>) - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "value": { - "description": "A value that can be string or number", - "anyOf": [ - {"type": "string"}, - {"type": "number"} - ] - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Should show enum badge (anyOf now renders as enum) - assert!(html.contains(">enum<"), "Should contain enum badge"); - assert!( - html.contains("type-string") || html.contains(">string<"), - "Should contain string type" - ); - assert!( - html.contains("type-number") || html.contains(">number<"), - "Should contain number type" - ); - } - - // Regression test: additionalProperties check should not fail on undefined - #[test] - fn test_schema_without_additional_properties() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "name": {"type": "string"} - } - })); - - let options = Options::default(); - // Should not error when additionalProperties is not defined - let result = generator.generate(&schema, &options); - assert!(result.is_ok()); - } - - // Test that descriptions are rendered as HTML (markdown processed) - #[test] - fn test_description_markdown_rendered() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "description": "This has **bold** and `code`", - "type": "object", - "properties": { - "field": { - "type": "string", - "description": "Field with *emphasis*" - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Schema description is used as title (markdown stripped for <title>) - assert!( - html.contains("This has bold and code"), - "Description should be used as title with markdown stripped" - ); - // The h1 should have rendered markdown - assert!( - html.contains("<strong>bold</strong>"), - "h1 should have rendered markdown" - ); - // Property description markdown is still rendered to HTML - assert!(html.contains("<em>emphasis</em>")); - } - - // Test Option<T> (anyOf with null) is rendered as optional badge - #[test] - fn test_option_t_rendered_as_optional() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "maybe_name": { - "anyOf": [ - { "type": "string" }, - { "type": "null" } - ] - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Should show "optional" badge - assert!(html.contains("optional"), "Should contain 'optional' badge"); - // Should show the string type - assert!( - html.contains("type-string") || html.contains(">string<"), - "Should contain string type badge" - ); - // Should NOT show "anyOf" badge for Option<T> - assert!( - !html.contains(">anyOf<"), - "Should not show anyOf badge for Option<T>" - ); - // Should NOT show variant markers - assert!( - !html.contains("Variant 1"), - "Should not show Variant markers for Option<T>" - ); - } - - // Test Option<T> with $ref - #[test] - fn test_option_t_with_ref() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "$defs": { - "MyType": { "type": "object", "description": "A custom type" } - }, - "properties": { - "maybe_type": { - "anyOf": [ - { "$ref": "#/$defs/MyType" }, - { "type": "null" } - ] - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Should show "optional" badge - assert!(html.contains("optional"), "Should contain 'optional' badge"); - // Should show the type reference - assert!(html.contains("MyType"), "Should contain MyType reference"); - // Should link to the type - assert!( - html.contains("href=\"#mytype\""), - "Should link to the type definition" - ); - } - - // Test that regular anyOf (not Option<T>) still shows all variants - #[test] - fn test_regular_anyof_shows_variants() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "value": { - "anyOf": [ - { "type": "string" }, - { "type": "number" } - ] - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Should show enum badge (anyOf now renders as enum) - assert!(html.contains(">enum<"), "Should show enum badge"); - // Should show variants summary - assert!( - html.contains("Enum variants (2)"), - "Should show variants summary" - ); - } - - // Test Option<T> with type array (e.g., type: ["boolean", "null"]) - #[test] - fn test_option_t_with_type_array() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "enabled": { - "type": ["boolean", "null"], - "description": "Enable feature" - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Should show "optional" badge - assert!(html.contains("optional"), "Should contain 'optional' badge"); - // Should show boolean type - assert!( - html.contains("type-boolean"), - "Should contain boolean type badge" - ); - // Should NOT show null type badge in the content (CSS class definition is OK) - // Check that there's no actual >null< badge text in the rendered property - assert!( - !html.contains(">null<"), - "Should not show null type badge text for Option<T>" - ); - } - - // Test outline section in sidebar - #[test] - fn test_outline_section_in_sidebar() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "alpha": { "type": "string" }, - "beta": { "type": "number" }, - "gamma": { "type": "boolean" } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Should have Outline section - assert!(html.contains("Outline"), "Should have Outline section"); - // Should list top-level properties with links - assert!( - html.contains("href=\"#alpha\""), - "Should link to alpha property" - ); - assert!( - html.contains("href=\"#beta\""), - "Should link to beta property" - ); - assert!( - html.contains("href=\"#gamma\""), - "Should link to gamma property" - ); - } - - // Test HashMap with integer key pattern displays friendly type - #[test] - fn test_hashmap_integer_key_display() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "layout_rules": { - "type": "object", - "patternProperties": { - "^\\d+$": { "type": "string" } - } - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Should show "integer" as the key type (with quotes to indicate string) - assert!( - html.contains("integer"), - "Should display 'integer' for ^\\d+$ pattern" - ); - assert!( - html.contains("key-type"), - "Should have key-type class for styling" - ); - // Should NOT show the raw regex pattern - assert!(!html.contains("^\\d+$"), "Should not show raw pattern"); - // Should show the arrow separator - assert!( - html.contains("→"), - "Should show arrow between key and value type" - ); - } - - // Test HashMap with string key pattern displays friendly type - #[test] - fn test_hashmap_string_key_display() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "string_map": { - "type": "object", - "patternProperties": { - ".*": { "type": "number" } - } - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Should show "string" for .* pattern - assert!( - html.contains(">string<"), - "Should display 'string' for .* pattern" - ); - // Should NOT show the raw pattern in the output - assert!(!html.contains(">.*<"), "Should not show raw .* pattern"); - } - - // Test HashMap with unknown pattern still shows the regex - #[test] - fn test_hashmap_unknown_pattern_shows_regex() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "custom_map": { - "type": "object", - "patternProperties": { - "^[a-z]+$": { "type": "string" } - } - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Unknown patterns should still show the regex - assert!( - html.contains("^[a-z]+$"), - "Should show unknown pattern as-is" - ); - assert!(html.contains("pattern"), "Should have pattern badge"); - } - - // Test: Array of primitives should not show "Array Items" dropdown - #[test] - fn test_array_of_primitives_no_dropdown() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "strings": { - "type": "array", - "items": { "type": "string" } - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Should show array and string badges - assert!(html.contains("type-array"), "Should have array badge"); - assert!(html.contains("type-string"), "Should have string badge"); - // Should NOT show Array Items dropdown - assert!( - !html.contains("Array Items"), - "Should not show redundant Array Items dropdown for simple types" - ); - } - - // Test: Homogeneous tuple should use compact [T; N] notation - #[test] - fn test_homogeneous_tuple_compact_notation() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "point": { - "type": "array", - "prefixItems": [ - { "type": "integer" }, - { "type": "integer" } - ], - "minItems": 2, - "maxItems": 2 - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Should show [array] badge followed by compact notation [integer; 2] - assert!(html.contains("type-array"), "Should have array badge"); - assert!( - html.contains("integer; 2"), - "Should show compact tuple notation [integer; 2]" - ); - // Should NOT show Tuple Items dropdown - assert!( - !html.contains("Tuple Items"), - "Should not show Tuple Items dropdown for homogeneous tuples" - ); - // Should NOT show min/max items constraints - assert!( - !html.contains("Min items"), - "Should not show Min items constraint for tuples" - ); - assert!( - !html.contains("Max items"), - "Should not show Max items constraint for tuples" - ); - } - - // Test: Heterogeneous tuple should show dropdown - #[test] - fn test_heterogeneous_tuple_shows_dropdown() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "mixed": { - "type": "array", - "prefixItems": [ - { "type": "string" }, - { "type": "integer" } - ] - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Should show tuple badge (heterogeneous) - assert!(html.contains(">tuple<"), "Should show tuple badge"); - // Should show Tuple Items dropdown - assert!( - html.contains("Tuple Items"), - "Should show Tuple Items dropdown for heterogeneous tuples" - ); - // Should show index markers - assert!(html.contains("[0]"), "Should show [0] index"); - assert!(html.contains("[1]"), "Should show [1] index"); - } - - // Test: String enum with descriptions uses variant divs - #[test] - fn test_string_enum_uses_variant_divs() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "mode": { - "oneOf": [ - { "type": "string", "const": "A", "description": "Option A" }, - { "type": "string", "const": "B", "description": "Option B" } - ] - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Should use variant divs - assert!( - html.contains("class=\"variant\""), - "Should use variant divs for string enum" - ); - // Should NOT use ul/li enum-values - assert!( - !html.contains("class=\"enum-values\""), - "Should not use ul.enum-values for string enum with descriptions" - ); - } - - // Test: Complex enum (object variants) shows enum badge, not oneOf - #[test] - fn test_complex_enum_shows_enum_badge() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "config": { - "oneOf": [ - { - "type": "object", - "properties": { "mode": { "type": "string" } } - }, - { - "type": "object", - "properties": { "level": { "type": "number" } } - } - ] - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Should show enum badge - assert!(html.contains(">enum<"), "Should show enum badge"); - // Should NOT show oneOf badge - assert!(!html.contains(">oneOf<"), "Should not show oneOf badge"); - // Should show "Enum variants" header - assert!( - html.contains("Enum variants"), - "Should show 'Enum variants' header" - ); - // Should NOT show "One of" header - assert!(!html.contains("One of"), "Should not show 'One of' header"); - } - - // Priority 1: Constraint rendering tests - - #[test] - fn test_format_constraint_renders() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email" - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - assert!( - html.contains("Format:") && html.contains("email"), - "Should render format constraint" - ); - } - - #[test] - fn test_pattern_constraint_renders() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "code": { - "type": "string", - "pattern": "^[A-Z]{3}$" - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - assert!( - html.contains("Pattern:") && html.contains("^[A-Z]{3}$"), - "Should render pattern constraint" - ); - } - - #[test] - fn test_min_max_constraints_render() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "age": { - "type": "integer", - "minimum": 0, - "maximum": 120 - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - assert!(html.contains("Min:"), "Should render minimum constraint"); - assert!(html.contains("Max:"), "Should render maximum constraint"); - } - - // Priority 1: allOf rendering tests - - #[test] - fn test_allof_renders_header() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "combined": { - "allOf": [ - { "type": "object", "properties": { "name": { "type": "string" } } }, - { "type": "object", "properties": { "age": { "type": "integer" } } } - ] - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - assert!( - html.contains("All of (2 schemas)"), - "Should render 'All of' header with count" - ); - } - - // Priority 1: const rendering tests - - #[test] - fn test_const_badge_renders() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "version": { - "const": "1.0.0" - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - assert!( - html.contains("type-const"), - "Should render const type badge" - ); - } - - #[test] - fn test_const_value_displays() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "api_version": { - "type": "string", - "const": "v2" - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Value is HTML-encoded as "v2" - assert!( - html.contains("const-value") && html.contains("v2"), - "Should display const value" - ); - } - - // Priority 1: deprecated badge rendering tests - - #[test] - fn test_deprecated_badge_renders() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "old_field": { - "type": "string", - "deprecated": true - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - assert!( - html.contains("class=\"badge deprecated\""), - "Should render deprecated badge" - ); - assert!( - html.contains(">deprecated<"), - "Should show 'deprecated' text" - ); - } - - // Priority 1: additionalProperties rendering tests - - #[test] - fn test_additional_properties_section_renders() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "metadata": { - "type": "object", - "additionalProperties": { - "type": "string" - } - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - assert!( - html.contains("Additional Properties"), - "Should render Additional Properties section" - ); - } - - // Priority 2: Edge case rendering tests - - #[test] - fn test_empty_properties_renders() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": {} - })); - - let options = Options::default(); - let result = generator.generate(&schema, &options); - - assert!(result.is_ok(), "Should not crash on empty properties"); - } - - #[test] - fn test_schema_without_title_uses_fallback() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "type": "object", - "properties": { - "name": { "type": "string" } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - assert!( - html.contains("Schema Documentation"), - "Should use fallback title" - ); - } - - #[test] - fn test_empty_definitions_renders() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "$defs": {} - })); - - let options = Options::default(); - let result = generator.generate(&schema, &options); - - assert!(result.is_ok(), "Should not crash on empty definitions"); - } - - #[test] - fn test_multiple_pattern_properties_all_render() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "config": { - "type": "object", - "patternProperties": { - "^[a-z]+$": { "type": "string" }, - "^[A-Z_]+$": { "type": "number" } - } - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Both patterns should be rendered (unknown patterns show as regex) - assert!(html.contains("^[a-z]+$"), "Should render first pattern"); - assert!(html.contains("^[A-Z_]+$"), "Should render second pattern"); - } - - // Priority 3: Type badge branch coverage - - #[test] - fn test_array_with_object_items_shows_both_badges() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "items": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { "type": "string" } - } - } - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - assert!(html.contains("type-array"), "Should show array badge"); - assert!(html.contains("type-object"), "Should show object badge"); - } - - #[test] - fn test_minlength_zero_renders() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "code": { - "type": "string", - "minLength": 0, - "maxLength": 10 - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // minLength: 0 should still render (not be falsely skipped) - assert!( - html.contains("Min length:") && html.contains("0"), - "Should render minLength: 0" - ); - assert!(html.contains("Max length:"), "Should render maxLength"); - } - - // Test: Homogeneous tuple with floats should display "float" instead of "number" - #[test] - fn test_tuple_float_display() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "point": { - "type": "array", - "prefixItems": [ - { "type": "number" }, - { "type": "number" } - ] - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Should show "float" instead of "number" for tuple display - assert!( - html.contains("float; 2"), - "Should display 'float; 2' for number tuples" - ); - assert!( - !html.contains("number; 2"), - "Should NOT display 'number; 2' for float tuples" - ); - assert!( - html.contains("type-float"), - "Should use type-float CSS class" - ); - } - - // Test: Homogeneous tuple with integers should still display "integer" - #[test] - fn test_tuple_integer_display_unchanged() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "coords": { - "type": "array", - "prefixItems": [ - { "type": "integer" }, - { "type": "integer" }, - { "type": "integer" } - ] - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Should still show "integer" for integer tuples - assert!( - html.contains("integer; 3"), - "Should display 'integer; 3' for integer tuples" - ); - assert!( - html.contains("type-integer"), - "Should use type-integer CSS class" - ); - } - - // Test: Float tuple with format (e.g., format: "double") still displays "float" - #[test] - fn test_tuple_float_with_format() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "bezier": { - "type": "array", - "prefixItems": [ - { "type": "number", "format": "double" }, - { "type": "number", "format": "double" }, - { "type": "number", "format": "double" }, - { "type": "number", "format": "double" } - ] - } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Should show "float" for number tuples regardless of format - assert!( - html.contains("float; 4"), - "Should display 'float; 4' for number tuples with format" - ); - } - - // ==================== Wrapper Type Rendering Tests ==================== - - // Test: Wrapper type with $ref renders inner type as link - #[test] - fn test_wrapper_type_renders_inner_ref() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "$defs": { - "InnerType": { - "type": "string", - "description": "The inner type" - }, - "WrapperType": { - "anyOf": [ - { - "type": "object", - "additionalProperties": { "$ref": "#/$defs/InnerType" } - }, - { "$ref": "#/$defs/InnerType" } - ] - } - }, - "properties": { - "config": { "$ref": "#/$defs/WrapperType" } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // WrapperType definition should show InnerType as a link - assert!( - html.contains("href=\"#innertype\""), - "Should link to inner type definition" - ); - // Should NOT show "enum" badge for wrapper type - // (Note: The wrapper type is referenced via $ref, so we check the definition section) - } - - // Test: Wrapper type with primitive renders primitive badge - #[test] - fn test_wrapper_type_renders_primitive_badge() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "$defs": { - "BoolWrapper": { - "anyOf": [ - { - "type": "object", - "additionalProperties": { "type": "boolean" } - }, - { "type": "boolean" } - ] - } - }, - "properties": { - "enabled": { "$ref": "#/$defs/BoolWrapper" } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Should show boolean type badge in the BoolWrapper definition - assert!( - html.contains("type-boolean"), - "Should show boolean type badge for wrapper with primitive inner type" - ); - } - - // Test: Wrapper type with integer constraints renders integer badge - #[test] - fn test_wrapper_type_with_integer_renders_correctly() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "$defs": { - "IntWrapper": { - "anyOf": [ - { - "type": "object", - "additionalProperties": { - "type": "integer", - "format": "uint64", - "minimum": 0 - } - }, - { - "type": "integer", - "format": "uint64", - "minimum": 0 - } - ] - } - }, - "properties": { - "duration": { "$ref": "#/$defs/IntWrapper" } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Should show integer type badge - assert!( - html.contains("type-integer"), - "Should show integer type badge for wrapper with integer inner type" - ); - } - - // Test: Non-wrapper anyOf still shows enum badge - #[test] - fn test_non_wrapper_anyof_still_shows_enum() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "$defs": { - "NotWrapper": { - "anyOf": [ - { - "type": "object", - "additionalProperties": { "type": "string" } - }, - { "type": "integer" } - ] - } - }, - "properties": { - "value": { "$ref": "#/$defs/NotWrapper" } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Should show enum badge since inner types don't match - assert!( - html.contains(">enum<"), - "Should show enum badge for non-wrapper anyOf" - ); - } - - // Test: Wrapper type does not show "Enum variants" dropdown - #[test] - fn test_wrapper_type_no_enum_variants_dropdown() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "$defs": { - "StringWrapper": { - "anyOf": [ - { - "type": "object", - "additionalProperties": { "type": "string" } - }, - { "type": "string" } - ] - } - }, - "properties": { - "name": { "$ref": "#/$defs/StringWrapper" } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Count occurrences of "Enum variants" - should not appear for wrapper types - // (The StringWrapper definition should not have an "Enum variants" dropdown) - let enum_variants_in_stringwrapper = html - .find("StringWrapper") - .map(|pos| { - let section = &html[pos..pos.min(html.len()).saturating_add(500)]; - section.contains("Enum variants") - }) - .unwrap_or(false); - - assert!( - !enum_variants_in_stringwrapper, - "Wrapper type should NOT show 'Enum variants' dropdown" - ); - } - - // Test: Wrapper type with $ref to AnimationStyle (like PerAnimationPrefixConfig3) - #[test] - fn test_wrapper_type_like_per_animation_prefix_config() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "$defs": { - "AnimationStyle": { - "type": "string", - "enum": ["Linear", "EaseIn", "EaseOut"] - }, - "PerAnimationPrefixConfig": { - "anyOf": [ - { - "type": "object", - "additionalProperties": { "$ref": "#/$defs/AnimationStyle" } - }, - { "$ref": "#/$defs/AnimationStyle" } - ] - } - }, - "properties": { - "style": { "$ref": "#/$defs/PerAnimationPrefixConfig" } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // The PerAnimationPrefixConfig definition should link to AnimationStyle - assert!( - html.contains("href=\"#animationstyle\""), - "Wrapper type should link to inner type (AnimationStyle)" - ); - } - - // Test: Wrapper types display base name without numeric suffix - #[test] - fn test_wrapper_type_display_name() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "$defs": { - "PerAnimationPrefixConfig": { - "anyOf": [ - { - "type": "object", - "additionalProperties": { "type": "boolean" } - }, - { "type": "boolean" } - ] - }, - "PerAnimationPrefixConfig2": { - "anyOf": [ - { - "type": "object", - "additionalProperties": { "type": "integer" } - }, - { "type": "integer" } - ] - }, - "PerAnimationPrefixConfig3": { - "anyOf": [ - { - "type": "object", - "additionalProperties": { "$ref": "#/$defs/AnimationStyle" } - }, - { "$ref": "#/$defs/AnimationStyle" } - ] - }, - "AnimationStyle": { - "type": "string", - "enum": ["Linear", "EaseIn"] - } - }, - "properties": { - "config1": { "$ref": "#/$defs/PerAnimationPrefixConfig" }, - "config2": { "$ref": "#/$defs/PerAnimationPrefixConfig2" }, - "config3": { "$ref": "#/$defs/PerAnimationPrefixConfig3" } - } - })); - - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Definition headers should show base name without numeric suffix - // PerAnimationPrefixConfig2 header should show "PerAnimationPrefixConfig" - - // Count definition-name headers containing "PerAnimationPrefixConfig" (base name) - // The HTML has whitespace/newlines in formatting - let header_pattern = "<h3 class=\"definition-name\">"; - let per_anim_header_count = html - .match_indices(header_pattern) - .filter(|(i, _)| { - let after = &html[*i + header_pattern.len()..]; - after.trim_start().starts_with("PerAnimationPrefixConfig") - }) - .count(); - - assert_eq!( - per_anim_header_count, 3, - "All 3 wrapper types should show 'PerAnimationPrefixConfig' in header (found {})", - per_anim_header_count - ); - - // Verify that PerAnimationPrefixConfig2 and PerAnimationPrefixConfig3 do NOT appear in headers - // (They should only appear in anchor IDs and href links) - assert!( - !html.contains("class=\"definition-name\">PerAnimationPrefixConfig2") && - !html.contains("class=\"definition-name\">\n PerAnimationPrefixConfig2"), - "Should NOT show numeric suffix 2 in definition header" - ); - assert!( - !html.contains("class=\"definition-name\">PerAnimationPrefixConfig3") && - !html.contains("class=\"definition-name\">\n PerAnimationPrefixConfig3"), - "Should NOT show numeric suffix 3 in definition header" - ); - - // Sidebar should also show base names (navigation uses display_name) - let sidebar_base_name_count = html.matches(">PerAnimationPrefixConfig<").count(); - assert!( - sidebar_base_name_count >= 3, - "Sidebar should show base name for wrapper types (found {})", - sidebar_base_name_count - ); - - // Anchors should still use full names for correct linking - assert!( - html.contains("id=\"peranimationprefixconfig\""), - "Anchor should use full name" - ); - assert!( - html.contains("id=\"peranimationprefixconfig2\""), - "Anchor should use full name with suffix" - ); - assert!( - html.contains("id=\"peranimationprefixconfig3\""), - "Anchor should use full name with suffix" - ); - } - - // Test: No broken anchor links in rendered output - #[test] - fn test_no_broken_anchor_links() { - use regex::Regex; - use std::collections::HashSet; - - let generator = Generator::new().unwrap(); - let schema_json = include_str!("../schema.json"); - let schema: Schema = serde_json::from_str(schema_json).unwrap(); - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Extract all href="#..." targets (excluding JavaScript template literals like ${...}) - let href_re = Regex::new(r##"href="#([^"]+)""##).unwrap(); - let hrefs: HashSet<String> = href_re - .captures_iter(&html) - .map(|c| c[1].to_string()) - .filter(|href| !href.starts_with("${")) // Exclude JS template literals - .collect(); - - // Extract all id="..." values - let id_re = Regex::new(r##"id="([^"]+)""##).unwrap(); - let ids: HashSet<String> = id_re - .captures_iter(&html) - .map(|c| c[1].to_string()) - .collect(); - - // Find broken links - let broken: Vec<&String> = hrefs.iter().filter(|href| !ids.contains(*href)).collect(); - - if !broken.is_empty() { - eprintln!("Broken anchor links found: {:?}", broken); - } - - assert!( - broken.is_empty(), - "Found {} broken anchor links: {:?}", - broken.len(), - broken.iter().take(20).collect::<Vec<_>>() - ); - } - - // Test: Modal has navigation buttons - #[test] - fn test_modal_has_navigation_buttons() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "field": { "type": "string" } - } - })); - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Should have modal navigation container - assert!( - html.contains("modal-nav"), - "Should have modal-nav container" - ); - // Should have back and forward buttons - assert!( - html.contains("data-dir=\"back\""), - "Should have back button" - ); - assert!( - html.contains("data-dir=\"forward\""), - "Should have forward button" - ); - // Should have navigation button class - assert!( - html.contains("modal-nav-btn"), - "Should have nav button class" - ); - } - - // Test: Modal nav buttons start disabled - #[test] - fn test_modal_nav_buttons_start_disabled() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "field": { "type": "string" } - } - })); - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Both nav buttons should start with disabled class - assert!( - html.contains("modal-nav-btn disabled"), - "Nav buttons should start disabled" - ); - } - - // Test: Modal has keyboard navigation - #[test] - fn test_modal_has_keyboard_navigation() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "field": { "type": "string" } - } - })); - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Should have Alt+Arrow keyboard handling - assert!(html.contains("altKey"), "Should handle Alt key modifier"); - assert!( - html.contains("ArrowLeft"), - "Should handle ArrowLeft for back" - ); - assert!( - html.contains("ArrowRight"), - "Should handle ArrowRight for forward" - ); - } - - // Test: Modal has history management - #[test] - fn test_modal_has_history_management() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "field": { "type": "string" } - } - })); - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // Should have history array and index - assert!( - html.contains("history=[]"), - "Should initialize history array" - ); - assert!( - html.contains("historyIndex=-1"), - "Should initialize history index" - ); - // Should have navigate function - assert!( - html.contains("navigateHistory"), - "Should have navigateHistory function" - ); - } - - // Test: Modal history cleared on close - #[test] - fn test_modal_history_cleared_on_close() { - let generator = Generator::new().unwrap(); - let schema = make_schema(json!({ - "title": "Test", - "type": "object", - "properties": { - "field": { "type": "string" } - } - })); - let options = Options::default(); - let html = generator.generate(&schema, &options).unwrap(); - - // closeModal function should reset history - // The function contains: history=[];historyIndex=-1; - assert!( - html.contains("history=[]") && html.contains("historyIndex=-1"), - "closeModal should reset history state" - ); - } -} diff --git a/src/identifiers.rs b/src/identifiers.rs deleted file mode 100644 index a434d55c..00000000 --- a/src/identifiers.rs +++ /dev/null @@ -1,371 +0,0 @@ -//! Single source of truth for all CSS classes and HTML IDs -//! -//! This module centralizes all identifier strings used in the generated HTML output. -//! By defining them here, we ensure consistency between Rust code, HTML templates, -//! CSS styles, and JavaScript. - -use serde::Serialize; -use struct_iterable::Iterable; - -/// Static HTML element IDs used for JavaScript interaction -#[allow(dead_code)] // Used by main crate, not build script -#[derive(Debug, Clone, Serialize)] -pub struct HtmlIds { - pub search: &'static str, - pub search_results: &'static str, - pub sidebar: &'static str, - pub sidebar_toggle: &'static str, - pub root_schema: &'static str, - pub definitions: &'static str, - pub modal_overlay: &'static str, -} - -/// All static HTML IDs -#[allow(dead_code)] // Used by main crate, not build script -pub const IDS: HtmlIds = HtmlIds { - search: "search", - search_results: "search-results", - sidebar: "sidebar", - sidebar_toggle: "sidebar-toggle", - root_schema: "root-schema", - definitions: "definitions", - modal_overlay: "modal-overlay", -}; - -/// CSS class names organized by category -#[derive(Debug, Clone, Serialize, Iterable)] -pub struct CssClasses { - // Layout - pub header: &'static str, - pub header_content: &'static str, - pub layout: &'static str, - pub main_content: &'static str, - - // Sidebar - pub sidebar: &'static str, - pub sidebar_open: &'static str, - pub sidebar_header: &'static str, - pub sidebar_toggle: &'static str, - pub sidebar_section: &'static str, - pub sidebar_section_title: &'static str, - - // Navigation - pub nav_list: &'static str, - pub nav_link: &'static str, - pub outline_list: &'static str, - pub outline_item: &'static str, - pub outline_children: &'static str, - - // Search - pub search_container: &'static str, - pub search_results: &'static str, - pub search_results_active: &'static str, - pub search_result_item: &'static str, - pub no_results: &'static str, - pub result_name: &'static str, - pub result_path: &'static str, - pub result_type: &'static str, - - // Schema sections - pub schema_section: &'static str, - pub schema_inline: &'static str, - pub properties_container: &'static str, - - // Property - pub property: &'static str, - pub property_header: &'static str, - pub property_name: &'static str, - pub pattern: &'static str, - - // Badges - pub badge: &'static str, - pub required: &'static str, - pub deprecated: &'static str, - pub optional: &'static str, - - // Type badges - pub type_badge: &'static str, - pub type_ref: &'static str, - - // Map display - pub map_key: &'static str, - pub key_type: &'static str, - pub map_arrow: &'static str, - - // Nested schema - pub nested_schema: &'static str, - pub enum_details: &'static str, - pub array_items: &'static str, - pub tuple_items: &'static str, - pub tuple_item: &'static str, - pub tuple_index: &'static str, - - // Constraints - pub constraints: &'static str, - pub constraint: &'static str, - pub label: &'static str, - - // Variants - pub variants: &'static str, - pub variant: &'static str, - pub enum_values: &'static str, - - // Values - pub default_value: &'static str, - pub const_value: &'static str, - - // Definition - pub definition: &'static str, - pub definition_name: &'static str, - pub highlight: &'static str, - - // Description - pub description: &'static str, - - // Usages - pub usages: &'static str, - pub usage_section: &'static str, - pub usage_list: &'static str, - - // Modal - pub modal_overlay: &'static str, - pub modal: &'static str, - pub modal_active: &'static str, - pub modal_header: &'static str, - pub modal_title: &'static str, - pub modal_close: &'static str, - pub modal_content: &'static str, - pub modal_nav: &'static str, - pub modal_nav_btn: &'static str, - pub modal_nav_disabled: &'static str, -} - -/// All CSS class names -pub const CSS: CssClasses = CssClasses { - // Layout - header: "header", - header_content: "header-content", - layout: "layout", - main_content: "main-content", - - // Sidebar - sidebar: "sidebar", - sidebar_open: "open", - sidebar_header: "sidebar-header", - sidebar_toggle: "sidebar-toggle", - sidebar_section: "sidebar-section", - sidebar_section_title: "sidebar-section-title", - - // Navigation - nav_list: "nav-list", - nav_link: "nav-link", - outline_list: "outline-list", - outline_item: "outline-item", - outline_children: "outline-children", - - // Search - search_container: "search-container", - search_results: "search-results", - search_results_active: "active", - search_result_item: "search-result-item", - no_results: "no-results", - result_name: "result-name", - result_path: "result-path", - result_type: "result-type", - - // Schema sections - schema_section: "schema-section", - schema_inline: "schema-inline", - properties_container: "properties-container", - - // Property - property: "property", - property_header: "property-header", - property_name: "property-name", - pattern: "pattern", - - // Badges - badge: "badge", - required: "required", - deprecated: "deprecated", - optional: "optional", - - // Type badges - type_badge: "type-badge", - type_ref: "type-ref", - - // Map display - map_key: "map-key", - key_type: "key-type", - map_arrow: "map-arrow", - - // Nested schema - nested_schema: "nested-schema", - enum_details: "enum-details", - array_items: "array-items", - tuple_items: "tuple-items", - tuple_item: "tuple-item", - tuple_index: "tuple-index", - - // Constraints - constraints: "constraints", - constraint: "constraint", - label: "label", - - // Variants - variants: "variants", - variant: "variant", - enum_values: "enum-values", - - // Values - default_value: "default-value", - const_value: "const-value", - - // Definition - definition: "definition", - definition_name: "definition-name", - highlight: "highlight", - - // Description - description: "description", - - // Usages - usages: "usages", - usage_section: "usage-section", - usage_list: "usage-list", - - // Modal - modal_overlay: "modal-overlay", - modal: "modal", - modal_active: "modal-active", - modal_header: "modal-header", - modal_title: "modal-title", - modal_close: "modal-close", - modal_content: "modal-content", - modal_nav: "modal-nav", - modal_nav_btn: "modal-nav-btn", - modal_nav_disabled: "disabled", -}; - -/// Type-specific badge class suffixes (used with type-badge prefix) -#[derive(Debug, Clone, Serialize, Iterable)] -pub struct TypeClasses { - pub string: &'static str, - pub number: &'static str, - pub integer: &'static str, - pub float: &'static str, - pub boolean: &'static str, - pub null: &'static str, - pub object: &'static str, - pub array: &'static str, - pub r#enum: &'static str, - pub union: &'static str, - pub r#const: &'static str, -} - -/// Type-specific badge classes -pub const TYPE_CLASSES: TypeClasses = TypeClasses { - string: "type-string", - number: "type-number", - integer: "type-integer", - float: "type-float", - boolean: "type-boolean", - null: "type-null", - object: "type-object", - array: "type-array", - r#enum: "type-enum", - union: "type-union", - r#const: "type-const", -}; - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_ids_are_valid_html_ids() { - // HTML IDs should not contain spaces and should be lowercase - assert!(!IDS.search.contains(' ')); - assert!(!IDS.search_results.contains(' ')); - assert!(!IDS.sidebar.contains(' ')); - assert!(!IDS.sidebar_toggle.contains(' ')); - } - - #[test] - fn test_css_classes_are_valid() { - // CSS classes should not contain spaces (multiple classes are separate fields) - assert!(!CSS.header.contains(' ')); - assert!(!CSS.property.contains(' ')); - assert!(!CSS.type_badge.contains(' ')); - } - - #[test] - fn test_type_classes_have_prefix() { - // All type classes should start with "type-" - assert!(TYPE_CLASSES.string.starts_with("type-")); - assert!(TYPE_CLASSES.integer.starts_with("type-")); - assert!(TYPE_CLASSES.array.starts_with("type-")); - } - - #[test] - fn test_modal_nav_classes_are_valid() { - // Modal navigation CSS classes should not contain spaces - assert!(!CSS.modal_nav.contains(' ')); - assert!(!CSS.modal_nav_btn.contains(' ')); - assert!(!CSS.modal_nav_disabled.contains(' ')); - } - - #[test] - fn test_all_css_classes_are_styled() { - use regex::Regex; - use std::collections::HashSet; - use std::fs; - use struct_iterable::Iterable; - - let css_content = - fs::read_to_string("src/templates/style.css").expect("Failed to read style.css"); - - // Extract all class names from CSS using regex - let class_regex = Regex::new(r"\.([a-zA-Z_][a-zA-Z0-9_-]*)").unwrap(); - let css_classes: HashSet<&str> = class_regex - .captures_iter(&css_content) - .filter_map(|c| c.get(1).map(|m| m.as_str())) - .collect(); - - // Verify enum-details specifically (was false-positive before fix) - assert!( - css_classes.contains("enum-details"), - "enum-details should be found in CSS (compound selector .enum-details .enum-values)" - ); - - // Dynamic prefixes to skip - let dynamic_prefixes = ["depth-"]; - - // Collect all defined classes and check they're in CSS - let mut missing: Vec<&str> = Vec::new(); - - for (_field_name, field_value) in CSS.iter() { - if let Some(class) = field_value.downcast_ref::<&str>() { - if !css_classes.contains(*class) - && !dynamic_prefixes.iter().any(|p| class.starts_with(p)) - { - missing.push(*class); - } - } - } - - for (_field_name, field_value) in TYPE_CLASSES.iter() { - if let Some(class) = field_value.downcast_ref::<&str>() { - if !css_classes.contains(*class) { - missing.push(*class); - } - } - } - - assert!( - missing.is_empty(), - "CSS classes defined but not styled: {:?}", - missing - ); - } -} diff --git a/src/lib.rs b/src/lib.rs index 18482ebf..e2e42b57 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,22 +2,20 @@ //! # schemars-docgen //! -//! Generate HTML documentation from `schemars::Schema` objects. +//! Generate MDX documentation from `schemars::Schema` objects. //! //! This library takes a JSON Schema (as produced by schemars) and generates -//! a self-contained HTML documentation page with: +//! MDX documentation suitable for Astro Starlight with: //! -//! - Responsive design (mobile, tablet, desktop) -//! - Dark/light mode following system preference -//! - Searchable properties -//! - Collapsible nested structures +//! - YAML frontmatter +//! - Starlight components //! - Markdown rendering for descriptions //! //! ## Usage //! //! ```rust,no_run //! use schemars::schema_for; -//! use schemars_docgen::{generate_html, Options}; +//! use schemars_docgen::{generate_mdx, MdxOptions}; //! //! #[derive(schemars::JsonSchema)] //! struct MyConfig { @@ -26,31 +24,18 @@ //! } //! //! let schema = schema_for!(MyConfig); -//! let options = Options::default(); -//! let html = generate_html(&schema, &options).unwrap(); +//! let options = MdxOptions::default(); +//! let mdx = generate_mdx(&schema, &options).unwrap(); //! ``` -mod generator; -pub mod identifiers; mod mdx_generator; mod prepare; -pub use generator::Generator; -pub use identifiers::CSS; -pub use identifiers::IDS; -pub use identifiers::TYPE_CLASSES; pub use mdx_generator::MdxGenerator; use schemars::Schema; use serde_json::Value; -/// Options for HTML generation -#[derive(Debug, Clone, Default)] -pub struct Options { - /// Override the schema title - pub title_override: Option<String>, -} - /// Options for MDX generation #[derive(Debug, Clone, Default)] pub struct MdxOptions { @@ -70,15 +55,6 @@ pub enum Error { Json(#[from] serde_json::Error), } -/// Generate HTML documentation from a schema -/// -/// This is the main entry point for the library. It takes a `schemars::Schema` -/// and returns a self-contained HTML string. -pub fn generate_html(schema: &Schema, options: &Options) -> Result<String, Error> { - let generator = Generator::new()?; - generator.generate(schema, options) -} - /// Generate MDX documentation from a schema /// /// This generates an MDX document suitable for use with Astro Starlight. @@ -425,7 +401,7 @@ mod tests { ) .unwrap(); - let result = generate_html(&schema, &Options::default()); + let result = generate_mdx(&schema, &MdxOptions::default()); assert!(result.is_ok(), "Should handle $ref in prefixItems"); } @@ -450,7 +426,7 @@ mod tests { ) .unwrap(); - let result = generate_html(&schema, &Options::default()); + let result = generate_mdx(&schema, &MdxOptions::default()); assert!( result.is_ok(), "Should handle mixed $ref and type in prefixItems" @@ -475,7 +451,7 @@ mod tests { ) .unwrap(); - let result = generate_html(&schema, &Options::default()); + let result = generate_mdx(&schema, &MdxOptions::default()); assert!(result.is_ok(), "Should handle anyOf in prefixItems"); } @@ -498,13 +474,7 @@ mod tests { ) .unwrap(); - let result = generate_html(&schema, &Options::default()); + let result = generate_mdx(&schema, &MdxOptions::default()); assert!(result.is_ok()); - let html = result.unwrap(); - // Homogeneous tuples should show as "array float; 3" not "Tuple Items" - assert!( - html.contains("float; 3") || html.contains("number; 3"), - "Homogeneous tuple should display as [T; N] format" - ); } } diff --git a/src/main.rs b/src/main.rs index 986db7ca..59d30f5d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,23 +1,10 @@ #![warn(clippy::all)] use clap::Parser; -use clap::ValueEnum; use schemars_docgen::MdxOptions; -use schemars_docgen::Options; -use schemars_docgen::generate_html; use schemars_docgen::generate_mdx; use std::path::PathBuf; -/// Output format for documentation generation -#[derive(Debug, Clone, Copy, Default, ValueEnum)] -enum Format { - /// HTML output (self-contained single file) - #[default] - Html, - /// MDX output for Astro Starlight - Mdx, -} - #[derive(Parser)] #[command(name = "schemars-docgen")] #[command(about = "Generate documentation from JSON Schema")] @@ -25,19 +12,15 @@ struct Cli { /// Input JSON Schema file input: PathBuf, - /// Output file (defaults to input filename with appropriate extension) + /// Output file (defaults to input filename with .mdx extension) #[arg(short, long)] output: Option<PathBuf>, - /// Output format - #[arg(short, long, default_value = "html")] - format: Format, - /// Schema title (overrides title from the schema) #[arg(short, long)] title: Option<String>, - /// Schema description (overrides description from the schema, MDX only) + /// Schema description (overrides description from the schema) #[arg(short, long)] description: Option<String>, } @@ -48,25 +31,15 @@ fn main() -> Result<(), Box<dyn std::error::Error>> { let schema_json = std::fs::read_to_string(&cli.input)?; let schema: schemars::Schema = serde_json::from_str(&schema_json)?; - let (output, extension) = match cli.format { - Format::Html => { - let options = Options { - title_override: cli.title, - }; - (generate_html(&schema, &options)?, "html") - } - Format::Mdx => { - let options = MdxOptions { - title_override: cli.title, - description_override: cli.description, - }; - (generate_mdx(&schema, &options)?, "mdx") - } + let options = MdxOptions { + title_override: cli.title, + description_override: cli.description, }; + let output = generate_mdx(&schema, &options)?; let output_path = cli.output.unwrap_or_else(|| { let mut path = cli.input.clone(); - path.set_extension(extension); + path.set_extension("mdx"); path }); diff --git a/src/mdx_generator.rs b/src/mdx_generator.rs index 6eadc807..ba4cde28 100644 --- a/src/mdx_generator.rs +++ b/src/mdx_generator.rs @@ -574,9 +574,9 @@ mod tests { "properties": { "value": { "anyOf": [ - { "type": "string" }, - { "type": "number" }, - { "type": "boolean" } + { "type": "string", "description": "A string value" }, + { "type": "number", "description": "A number value" }, + { "type": "boolean", "description": "A boolean value" } ] } } @@ -585,10 +585,24 @@ mod tests { let options = MdxOptions::default(); let mdx = generator.generate(&schema, &options).unwrap(); - // Should show all variant types - assert!(mdx.contains("string"), "Should contain string variant"); - assert!(mdx.contains("number"), "Should contain number variant"); - assert!(mdx.contains("boolean"), "Should contain boolean variant"); + // Should show variant descriptions (not type badges for enum variants) + assert!( + mdx.contains("A string value"), + "Should contain string variant description" + ); + assert!( + mdx.contains("A number value"), + "Should contain number variant description" + ); + assert!( + mdx.contains("A boolean value"), + "Should contain boolean variant description" + ); + // Should show enum variants section + assert!( + mdx.contains("Enum variants"), + "Should show enum variants header" + ); } #[test] @@ -924,4 +938,620 @@ mod tests { let result = escape_braces_outside_code("`{a}` and `{b}` with {c}"); assert_eq!(result, "`{a}` and `{b}` with \\{c\\}"); } + + // ========================================================================= + // Enum Pattern Tests - Ensure Value: is never rendered twice + // See ENUMS.md for full pattern documentation + // ========================================================================= + + /// Helper to count occurrences of a pattern in a string + fn count_occurrences(haystack: &str, needle: &str) -> usize { + haystack.matches(needle).count() + } + + /// Helper to count occurrences of "Value:" followed by a specific value + fn count_value_occurrences(mdx: &str, value: &str) -> usize { + // Look for patterns like: **Value:** `"Horizontal"` + let pattern = format!("**Value:** `\"{}\"`", value); + count_occurrences(mdx, &pattern) + } + + // Pattern 1: Simple Unit Enums (String Constants) + // oneOf with {type: "string", const: "Value"} + #[test] + fn test_pattern1_simple_unit_enum_no_duplicate_value() { + let generator = MdxGenerator::new().unwrap(); + let schema = make_schema(json!({ + "title": "Test", + "type": "object", + "properties": { + "axis": { + "description": "Axis selection", + "oneOf": [ + { "description": "Horizontal axis", "type": "string", "const": "Horizontal" }, + { "description": "Vertical axis", "type": "string", "const": "Vertical" }, + { "description": "Both axes", "type": "string", "const": "HorizontalAndVertical" } + ] + } + } + })); + + let options = MdxOptions::default(); + let mdx = generator.generate(&schema, &options).unwrap(); + + // Each variant's Value: should appear exactly once + assert_eq!( + count_value_occurrences(&mdx, "Horizontal"), + 1, + "Horizontal Value: should appear exactly once. MDX:\n{}", + mdx + ); + assert_eq!( + count_value_occurrences(&mdx, "Vertical"), + 1, + "Vertical Value: should appear exactly once. MDX:\n{}", + mdx + ); + assert_eq!( + count_value_occurrences(&mdx, "HorizontalAndVertical"), + 1, + "HorizontalAndVertical Value: should appear exactly once. MDX:\n{}", + mdx + ); + } + + // Pattern 2: Unit Enum with Default Value + // Same as Pattern 1 but with "default" field at enum level + #[test] + fn test_pattern2_unit_enum_with_default_no_duplicate_value() { + let generator = MdxGenerator::new().unwrap(); + let schema = make_schema(json!({ + "title": "Test", + "type": "object", + "properties": { + "layout": { + "description": "A predefined layout", + "default": "BSP", + "oneOf": [ + { "description": "BSP Layout", "type": "string", "const": "BSP" }, + { "description": "Columns Layout", "type": "string", "const": "Columns" } + ] + } + } + })); + + let options = MdxOptions::default(); + let mdx = generator.generate(&schema, &options).unwrap(); + + assert_eq!( + count_value_occurrences(&mdx, "BSP"), + 1, + "BSP Value: should appear exactly once. MDX:\n{}", + mdx + ); + assert_eq!( + count_value_occurrences(&mdx, "Columns"), + 1, + "Columns Value: should appear exactly once. MDX:\n{}", + mdx + ); + } + + // Pattern 3: Mixed Enum (Unit Variants + Newtype Variants) + // oneOf with unit variants as {type: "string", const: "Name"} and + // newtype variants as objects with variant name as property key + #[test] + fn test_pattern3_mixed_enum_no_duplicate_value() { + let generator = MdxGenerator::new().unwrap(); + let schema = make_schema(json!({ + "title": "Test", + "type": "object", + "properties": { + "format": { + "description": "Date format", + "oneOf": [ + { "description": "Month/Date/Year format", "type": "string", "const": "MonthDateYear" }, + { "description": "Year-Month-Date format", "type": "string", "const": "YearMonthDate" }, + { + "title": "Custom", + "description": "Custom format", + "type": "object", + "properties": { + "Custom": { "type": "string" } + }, + "additionalProperties": false, + "required": ["Custom"] + } + ] + } + } + })); + + let options = MdxOptions::default(); + let mdx = generator.generate(&schema, &options).unwrap(); + + assert_eq!( + count_value_occurrences(&mdx, "MonthDateYear"), + 1, + "MonthDateYear Value: should appear exactly once. MDX:\n{}", + mdx + ); + assert_eq!( + count_value_occurrences(&mdx, "YearMonthDate"), + 1, + "YearMonthDate Value: should appear exactly once. MDX:\n{}", + mdx + ); + } + + // Pattern 4a: Untagged with Primitives + // anyOf with {type: "integer"} and {$ref: "..."} + #[test] + fn test_pattern4a_untagged_primitives_no_duplicate_value() { + let generator = MdxGenerator::new().unwrap(); + let schema = make_schema(json!({ + "title": "Test", + "type": "object", + "$defs": { + "MonitorConfig": { "type": "object", "properties": { "name": { "type": "string" } } } + }, + "properties": { + "monitor": { + "description": "Monitor configuration or index", + "anyOf": [ + { "description": "The monitor index", "type": "integer", "format": "uint", "minimum": 0 }, + { "description": "The full config", "$ref": "#/$defs/MonitorConfig" } + ] + } + } + })); + + let options = MdxOptions::default(); + let mdx = generator.generate(&schema, &options).unwrap(); + + // For anyOf with primitives, we should see the type badge, not duplicate values + // Count total **Value:** occurrences - should not have duplicates + let total_value_lines = count_occurrences(&mdx, "**Value:**"); + // Each variant should have at most one Value: line + assert!( + total_value_lines <= 2, + "Should have at most 2 Value: lines (one per variant). Found {}. MDX:\n{}", + total_value_lines, + mdx + ); + } + + // Pattern 4b: Untagged with Multiple Struct Refs + #[test] + fn test_pattern4b_untagged_multiple_refs_no_duplicate_value() { + let generator = MdxGenerator::new().unwrap(); + let schema = make_schema(json!({ + "title": "Test", + "type": "object", + "$defs": { + "IndividualSpacing": { "type": "object" }, + "GroupedSpacing": { "type": "object" } + }, + "properties": { + "spacing": { + "description": "Spacing kind", + "anyOf": [ + { "description": "All sides", "type": "number", "format": "float" }, + { "description": "Individual", "$ref": "#/$defs/IndividualSpacing" }, + { "description": "Grouped", "$ref": "#/$defs/GroupedSpacing" } + ] + } + } + })); + + let options = MdxOptions::default(); + let mdx = generator.generate(&schema, &options).unwrap(); + + let total_value_lines = count_occurrences(&mdx, "**Value:**"); + assert!( + total_value_lines <= 3, + "Should have at most 3 Value: lines. Found {}. MDX:\n{}", + total_value_lines, + mdx + ); + } + + // Pattern 4c: Untagged with Two $refs + #[test] + fn test_pattern4c_untagged_two_refs_no_duplicate_value() { + let generator = MdxGenerator::new().unwrap(); + let schema = make_schema(json!({ + "title": "Test", + "type": "object", + "$defs": { + "Rgb": { "type": "object" }, + "Hex": { "type": "string" } + }, + "properties": { + "colour": { + "description": "Colour representation", + "anyOf": [ + { "description": "RGB", "$ref": "#/$defs/Rgb" }, + { "description": "Hex", "$ref": "#/$defs/Hex" } + ] + } + } + })); + + let options = MdxOptions::default(); + let mdx = generator.generate(&schema, &options).unwrap(); + + let total_value_lines = count_occurrences(&mdx, "**Value:**"); + assert!( + total_value_lines <= 2, + "Should have at most 2 Value: lines. Found {}. MDX:\n{}", + total_value_lines, + mdx + ); + } + + // Pattern 4d: Untagged with Single vs Array + #[test] + fn test_pattern4d_untagged_single_vs_array_no_duplicate_value() { + let generator = MdxGenerator::new().unwrap(); + let schema = make_schema(json!({ + "title": "Test", + "type": "object", + "$defs": { + "IdWithIdentifier": { "type": "object" } + }, + "properties": { + "rule": { + "description": "Matching rule", + "anyOf": [ + { "description": "Simple rule", "$ref": "#/$defs/IdWithIdentifier" }, + { "description": "Composite rule", "type": "array", "items": { "$ref": "#/$defs/IdWithIdentifier" } } + ] + } + } + })); + + let options = MdxOptions::default(); + let mdx = generator.generate(&schema, &options).unwrap(); + + let total_value_lines = count_occurrences(&mdx, "**Value:**"); + assert!( + total_value_lines <= 2, + "Should have at most 2 Value: lines. Found {}. MDX:\n{}", + total_value_lines, + mdx + ); + } + + // Pattern 4e: Untagged with Tuple + #[test] + fn test_pattern4e_untagged_tuple_no_duplicate_value() { + let generator = MdxGenerator::new().unwrap(); + let schema = make_schema(json!({ + "title": "Test", + "type": "object", + "properties": { + "spacing_options": { + "description": "Grouped spacing options", + "anyOf": [ + { "description": "Symmetrical", "type": "number", "format": "float" }, + { + "description": "Split spacing", + "type": "array", + "maxItems": 2, + "minItems": 2, + "prefixItems": [ + { "type": "number", "format": "float" }, + { "type": "number", "format": "float" } + ] + } + ] + } + } + })); + + let options = MdxOptions::default(); + let mdx = generator.generate(&schema, &options).unwrap(); + + let total_value_lines = count_occurrences(&mdx, "**Value:**"); + assert!( + total_value_lines <= 2, + "Should have at most 2 Value: lines. Found {}. MDX:\n{}", + total_value_lines, + mdx + ); + } + + // Pattern 5: Internally Tagged Enum (Struct Variants with Discriminator) + // oneOf with discriminator field having const value + #[test] + fn test_pattern5_internally_tagged_no_duplicate_value() { + let generator = MdxGenerator::new().unwrap(); + let schema = make_schema(json!({ + "title": "Test", + "type": "object", + "$defs": { + "ThemeName": { "type": "string" } + }, + "properties": { + "theme": { + "description": "Theme selection", + "oneOf": [ + { + "title": "Catppuccin", + "description": "A catppuccin theme", + "type": "object", + "properties": { + "palette": { "type": "string", "const": "Catppuccin" }, + "name": { "$ref": "#/$defs/ThemeName" } + }, + "required": ["palette", "name"] + }, + { + "title": "Base16", + "type": "object", + "properties": { + "palette": { "type": "string", "const": "Base16" }, + "name": { "$ref": "#/$defs/ThemeName" } + }, + "required": ["palette", "name"] + } + ] + } + } + })); + + let options = MdxOptions::default(); + let mdx = generator.generate(&schema, &options).unwrap(); + + // The discriminator const values should not cause duplicate Value: lines + // Catppuccin and Base16 are titles, not const values to be rendered + let total_value_lines = count_occurrences(&mdx, "**Value:**"); + // With internally tagged, we typically don't render Value: for the discriminator + // but we might render it for the variant as a whole + assert!( + total_value_lines <= 2, + "Should have reasonable Value: count. Found {}. MDX:\n{}", + total_value_lines, + mdx + ); + } + + // Pattern 6: Internally Tagged Enum with Flattened Newtype Variants + // oneOf with properties + $ref at same level + #[test] + fn test_pattern6_internally_tagged_flatten_no_duplicate_value() { + let generator = MdxGenerator::new().unwrap(); + let schema = make_schema(json!({ + "title": "Test", + "type": "object", + "$defs": { + "GroupingConfig": { + "type": "object", + "properties": { + "style": { "type": "string" } + } + } + }, + "properties": { + "grouping": { + "description": "Grouping mode", + "oneOf": [ + { + "title": "None", + "description": "No grouping", + "type": "object", + "properties": { + "kind": { "type": "string", "const": "None" } + }, + "required": ["kind"] + }, + { + "title": "Bar", + "description": "Bar grouping", + "type": "object", + "properties": { + "kind": { "type": "string", "const": "Bar" } + }, + "$ref": "#/$defs/GroupingConfig", + "required": ["kind"] + } + ] + } + } + })); + + let options = MdxOptions::default(); + let mdx = generator.generate(&schema, &options).unwrap(); + + let total_value_lines = count_occurrences(&mdx, "**Value:**"); + assert!( + total_value_lines <= 2, + "Should have reasonable Value: count. Found {}. MDX:\n{}", + total_value_lines, + mdx + ); + } + + // Pattern 7: Externally Tagged Enum (Newtype Variants Only) + // oneOf with variant name as property key + #[test] + fn test_pattern7_externally_tagged_no_duplicate_value() { + let generator = MdxGenerator::new().unwrap(); + let schema = make_schema(json!({ + "title": "Test", + "type": "object", + "$defs": { + "ApplicationsConfig": { "type": "object" }, + "BatteryConfig": { "type": "object" } + }, + "properties": { + "widget": { + "description": "Widget configuration", + "oneOf": [ + { + "title": "Applications", + "description": "Applications widget", + "type": "object", + "properties": { + "Applications": { "$ref": "#/$defs/ApplicationsConfig" } + }, + "additionalProperties": false, + "required": ["Applications"] + }, + { + "title": "Battery", + "type": "object", + "properties": { + "Battery": { "$ref": "#/$defs/BatteryConfig" } + }, + "additionalProperties": false, + "required": ["Battery"] + } + ] + } + } + })); + + let options = MdxOptions::default(); + let mdx = generator.generate(&schema, &options).unwrap(); + + let total_value_lines = count_occurrences(&mdx, "**Value:**"); + assert!( + total_value_lines <= 2, + "Should have reasonable Value: count. Found {}. MDX:\n{}", + total_value_lines, + mdx + ); + } + + // Pattern 9: Untagged Hybrid Enum (Unit Variants + $ref Fallback) + // anyOf mixing const strings + $ref + #[test] + fn test_pattern9_untagged_hybrid_no_duplicate_value() { + let generator = MdxGenerator::new().unwrap(); + let schema = make_schema(json!({ + "title": "Test", + "type": "object", + "$defs": { + "DisplayFormat": { + "oneOf": [ + { "type": "string", "const": "Text" }, + { "type": "string", "const": "Icon" } + ] + } + }, + "properties": { + "format": { + "description": "Display format", + "anyOf": [ + { "description": "All icons", "type": "string", "const": "AllIcons" }, + { "description": "All icons and text", "type": "string", "const": "AllIconsAndText" }, + { "$ref": "#/$defs/DisplayFormat" } + ] + } + } + })); + + let options = MdxOptions::default(); + let mdx = generator.generate(&schema, &options).unwrap(); + + assert_eq!( + count_value_occurrences(&mdx, "AllIcons"), + 1, + "AllIcons Value: should appear exactly once. MDX:\n{}", + mdx + ); + assert_eq!( + count_value_occurrences(&mdx, "AllIconsAndText"), + 1, + "AllIconsAndText Value: should appear exactly once. MDX:\n{}", + mdx + ); + } + + // Pattern 10: Generic Enum Instantiations + // anyOf with {additionalProperties: T} + T + #[test] + fn test_pattern10_generic_enum_no_duplicate_value() { + let generator = MdxGenerator::new().unwrap(); + let schema = make_schema(json!({ + "title": "Test", + "type": "object", + "properties": { + "config": { + "description": "Per-animation config", + "anyOf": [ + { + "description": "Prefixed config", + "type": "object", + "additionalProperties": { "type": "boolean" } + }, + { + "description": "Global config", + "type": "boolean" + } + ] + } + } + })); + + let options = MdxOptions::default(); + let mdx = generator.generate(&schema, &options).unwrap(); + + let total_value_lines = count_occurrences(&mdx, "**Value:**"); + assert!( + total_value_lines <= 2, + "Should have at most 2 Value: lines. Found {}. MDX:\n{}", + total_value_lines, + mdx + ); + } + + // Test for the specific issue reported - Pattern 1 with Axis enum + #[test] + fn test_axis_enum_exact_case_no_duplicate_value() { + let generator = MdxGenerator::new().unwrap(); + // This is the exact schema structure from the bug report + let schema = make_schema(json!({ + "title": "Test", + "type": "object", + "$defs": { + "Axis": { + "description": "Axis", + "oneOf": [ + { "description": "Horizontal axis", "type": "string", "const": "Horizontal" }, + { "description": "Vertical axis", "type": "string", "const": "Vertical" }, + { "description": "Both horizontal and vertical axes", "type": "string", "const": "HorizontalAndVertical" } + ] + } + }, + "properties": { + "axis": { "$ref": "#/$defs/Axis" } + } + })); + + let options = MdxOptions::default(); + let mdx = generator.generate(&schema, &options).unwrap(); + + // The bug was that each variant's Value: was appearing twice + assert_eq!( + count_value_occurrences(&mdx, "Horizontal"), + 1, + "Horizontal Value: should appear exactly once (was appearing twice). MDX:\n{}", + mdx + ); + assert_eq!( + count_value_occurrences(&mdx, "Vertical"), + 1, + "Vertical Value: should appear exactly once (was appearing twice). MDX:\n{}", + mdx + ); + assert_eq!( + count_value_occurrences(&mdx, "HorizontalAndVertical"), + 1, + "HorizontalAndVertical Value: should appear exactly once (was appearing twice). MDX:\n{}", + mdx + ); + } } diff --git a/src/prepare.rs b/src/prepare.rs index 9bbbefaf..0abacbc5 100644 --- a/src/prepare.rs +++ b/src/prepare.rs @@ -126,12 +126,11 @@ fn extract_type_ref(map: &Map<String, Value>) -> Option<String> { if null_count == 1 { // Find the non-null variant with a $ref for variant in variants { - if variant.get("type").and_then(|t| t.as_str()) != Some("null") { - if let Some(ref_str) = variant.get("$ref").and_then(|v| v.as_str()) - && let Some(type_name) = ref_str.strip_prefix("#/$defs/") - { - return Some(type_name.to_string()); - } + if variant.get("type").and_then(|t| t.as_str()) != Some("null") + && let Some(ref_str) = variant.get("$ref").and_then(|v| v.as_str()) + && let Some(type_name) = ref_str.strip_prefix("#/$defs/") + { + return Some(type_name.to_string()); } } } @@ -645,6 +644,12 @@ fn build_outline_tree( .and_then(|v| v.as_object()) { for (name, prop) in props { + // Skip properties with const values (discriminator fields in internally tagged enums) + // These are shown as variant headings in templates, not as rendered properties + if prop.get("const").is_some() { + continue; + } + // Build the anchor path using the resolved anchor base let child_anchor_path = if anchor_base.is_empty() { name.clone() diff --git a/src/templates/base.html b/src/templates/base.html deleted file mode 100644 index 443e0214..00000000 --- a/src/templates/base.html +++ /dev/null @@ -1,189 +0,0 @@ -{%- import "macros.html" as macros -%} -<!doctype html> -<html lang="en"> - <head> - <meta charset="UTF-8" /> - <meta name="viewport" content="width=device-width, initial-scale=1.0" /> - <title>{{ title | default(value="Schema Documentation") }} - - - -
-
-

- {{ title_html | default(value="Schema Documentation") | safe - }} -

-
- -
-
-
-
-
- -
-
-

Configuration

- {%- if schema.properties -%} -
- {%- for prop_name, prop in schema.properties -%} {%- set - is_required = prop_name in required_set -%} {{ - macros::render_property(name=prop_name, node=prop, - required=is_required, depth=0, path=prop_name) }} {%- - endfor -%} -
- {%- endif -%} -
- {%- if schema["$defs"] -%} -
-

Type Definitions

- {%- for def_name, def in schema["$defs"] -%} -
-

- {{ def._display_name | default(value=def_name) }} -

- {%- if def.description_html %} -
- {{ def.description_html | safe }} -
- {% endif -%} {{ macros::render_schema(node=def, depth=0, - path=def_name) }} {# Usages section at bottom - use - embedded _usages to avoid lookup issues with special - chars #} {%- if def._usages and - (def._usages.config_usages | length > 0 or - def._usages.type_references | length > 0) -%} -
- {%- if def._usages.config_usages | length > 0 -%} -
-

Configuration Usage

-
    - {%- for usage in def._usages.config_usages - -%} -
  • - {{ usage.path }} -
  • - {%- endfor -%} -
-
- {%- endif -%} {%- if def._usages.type_references | - length > 0 -%} -
-

Referenced by

-
    - {%- for ref in def._usages.type_references - -%} {%- set ref_display = - display_names[ref.type_name] | - default(value=ref.type_name) -%} -
  • - {{ ref_display }} -
  • - {%- endfor -%} -
-
- {%- endif -%} -
- {%- endif -%} -
- {%- endfor -%} -
- {%- endif -%} -
-
-
-
-
-
- - -
-

- -
-
-
-
- - - diff --git a/src/templates/macros.html b/src/templates/macros.html deleted file mode 100644 index 8f6f903c..00000000 --- a/src/templates/macros.html +++ /dev/null @@ -1,372 +0,0 @@ -{# Render a hierarchical outline item with collapsible children #} -{% macro render_outline_item(entry, depth) %} -{%- if entry.children | length > 0 -%} -
  • -
    - - {{ entry.name }} - -
      - {%- for child in entry.children -%} - {{ self::render_outline_item(entry=child, depth=depth + 1) }} - {%- endfor -%} -
    -
    -
  • -{%- else -%} -
  • - {{ entry.name }} -
  • -{%- endif -%} -{% endmacro render_outline_item %} - -{# Render a property with its name and schema #} -{# Note: Using 'node' instead of 'schema' to avoid conflict with global context #} -{% macro render_property(name, node, required, depth, path) %} -{%- if depth < 10 -%} -
    -
    - {{ name }} - {%- if required %}required{% endif -%} - {%- if node.deprecated %}deprecated{% endif -%} - {{ self::render_type_badge(node=node) }} -
    - {%- if node.description_html %}
    {{ node.description_html | safe }}
    {% endif -%} - {{ self::render_constraints(node=node) }} - {%- if node.default %}
    Default: {% if node._default_ref and schema["$defs"][node._default_ref] %}{{ node.default | json_encode() }}{% else %}{{ node.default | json_encode() }}{% endif %}
    {% endif -%} - {{ self::render_schema_body(node=node, depth=depth, path=path) }} -
    -{%- else -%} -
    Schema nested too deeply. See type definition.
    -{%- endif -%} -{% endmacro render_property %} - -{# Render the type badge for a schema #} -{% macro render_type_badge(node) %} -{%- if node["$ref"] -%} - {%- set ref_name = node["$ref"] | replace(from="#/$defs/", to="") -%} - {%- set display = display_names[ref_name] | default(value=ref_name) -%} - {%- if schema["$defs"][ref_name] -%} - {%- set ref_def = schema["$defs"][ref_name] -%} - {{ display }} - {%- if ref_def._wrapper_inner %} {{ self::render_type_badge(node=ref_def._wrapper_inner) }}{%- endif -%} - {%- else -%} - $ref - {%- endif -%} -{%- elif node.type -%} - {%- if node.type is string -%} - {%- if node.type == "array" and node.prefixItems -%} - {# Check if all prefixItems have the same type (homogeneous tuple) #} - {%- set first_type = node.prefixItems | first -%} - {%- set_global is_homogeneous = true -%} - {%- for item in node.prefixItems -%} - {%- if item.type is defined and first_type.type is defined -%} - {%- if item.type != first_type.type -%} - {%- set_global is_homogeneous = false -%} - {%- endif -%} - {%- else -%} - {# If either lacks a direct type (uses $ref, anyOf, etc.), not homogeneous #} - {%- set_global is_homogeneous = false -%} - {%- endif -%} - {%- endfor -%} - {%- if is_homogeneous and first_type.type -%} - array {% if first_type.type == "number" %}float; {{ node.prefixItems | length }}{% else %}{{ first_type.type }}; {{ node.prefixItems | length }}{% endif %} - {%- else -%} - array tuple - {%- endif -%} - {%- elif node.type == "array" and node.items -%} - {# Show array with item type as separate badge #} - array {{ self::render_type_badge(node=node.items) }} - {%- else -%} - {{ node.type }} - {%- endif -%} - {%- else -%} - {# Check for Option pattern: type array with exactly 2 types where one is null #} - {%- if node.type | length == 2 and "null" in node.type -%} - optional - {%- for t in node.type -%} - {%- if t != "null" %} {% if t == "array" and node.items %}array {{ self::render_type_badge(node=node.items) }}{% else %}{{ t }}{% endif %} - {%- endif -%} - {%- endfor -%} - {%- else -%} - {%- for t in node.type %} {{ t }}{%- endfor -%} - {%- endif -%} - {%- endif -%} -{%- elif node.anyOf -%} - {# Check for wrapper type pattern first (detected in prepare.rs) #} - {%- if node._wrapper_type -%} - {# Wrapper type: show inner type badge (type name shown separately in type definitions) #} - {{ self::render_type_badge(node=node._wrapper_inner) }} - {# Check for Option pattern: anyOf with exactly 2 variants where one is null #} - {%- elif node.anyOf | length == 2 -%} - {%- set first = node.anyOf | first -%} - {%- set second = node.anyOf | last -%} - {%- if second.type and second.type == "null" -%} - optional {{ self::render_type_badge(node=first) }} - {%- elif first.type and first.type == "null" -%} - optional {{ self::render_type_badge(node=second) }} - {%- else -%} - {# Check if all variants are string const (enum pattern) #} - {%- set_global is_string_enum = true -%} - {%- for variant in node.anyOf -%} - {%- if variant.type and variant.type == "string" and variant.const -%} - {# valid string const #} - {%- else -%} - {%- set_global is_string_enum = false -%} - {%- endif -%} - {%- endfor -%} - {%- if is_string_enum -%} - string enum - {%- else -%} - enum - {%- endif -%} - {%- endif -%} - {%- else -%} - {# Check if all variants are string const (enum pattern) #} - {%- set_global is_string_enum = true -%} - {%- for variant in node.anyOf -%} - {%- if variant.type and variant.type == "string" and variant.const -%} - {# valid string const #} - {%- else -%} - {%- set_global is_string_enum = false -%} - {%- endif -%} - {%- endfor -%} - {%- if is_string_enum -%} - string enum - {%- else -%} - enum - {%- endif -%} - {%- endif -%} -{%- elif node.oneOf -%} - {# Check if all variants are string const (enum pattern from schemars with doc comments) #} - {%- set_global is_string_enum = true -%} - {%- for variant in node.oneOf -%} - {%- if variant.type and variant.type == "string" and variant.const -%} - {# This variant is a string const, keep is_string_enum true #} - {%- else -%} - {%- set_global is_string_enum = false -%} - {%- endif -%} - {%- endfor -%} - {%- if is_string_enum -%} - string enum - {%- else -%} - enum - {%- endif -%} -{%- elif node.allOf -%} - allOf -{%- elif node.const -%} - const -{%- elif node.enum -%} - enum -{%- endif -%} -{% endmacro render_type_badge %} - -{# Render constraints like min, max, pattern, format #} -{% macro render_constraints(node) %} -{# Check if this is a homogeneous tuple - skip minItems/maxItems if so #} -{%- set_global skip_item_constraints = false -%} -{%- if node.prefixItems -%} - {%- set first_type = node.prefixItems | first -%} - {%- set_global is_homogeneous = true -%} - {%- for item in node.prefixItems -%} - {%- if item.type is defined and first_type.type is defined -%} - {%- if item.type != first_type.type -%} - {%- set_global is_homogeneous = false -%} - {%- endif -%} - {%- else -%} - {# If either lacks a direct type (uses $ref, anyOf, etc.), not homogeneous #} - {%- set_global is_homogeneous = false -%} - {%- endif -%} - {%- endfor -%} - {%- if is_homogeneous and first_type.type -%} - {%- set_global skip_item_constraints = true -%} - {%- endif -%} -{%- endif -%} -{%- if node.format or node.pattern or node.minimum is defined or node.maximum is defined or node.minLength is defined or node.maxLength is defined or (node.minItems is defined and not skip_item_constraints) or (node.maxItems is defined and not skip_item_constraints) -%} -
    - {%- if node.format %}Format: {{ node.format }}{% endif -%} - {%- if node.pattern %}Pattern: {{ node.pattern }}{% endif -%} - {%- if node.minimum is defined %}Min: {{ node.minimum }}{% endif -%} - {%- if node.maximum is defined %}Max: {{ node.maximum }}{% endif -%} - {%- if node.minLength is defined %}Min length: {{ node.minLength }}{% endif -%} - {%- if node.maxLength is defined %}Max length: {{ node.maxLength }}{% endif -%} - {%- if node.minItems is defined and not skip_item_constraints %}Min items: {{ node.minItems }}{% endif -%} - {%- if node.maxItems is defined and not skip_item_constraints %}Max items: {{ node.maxItems }}{% endif -%} -
    -{%- endif -%} -{% endmacro render_constraints %} - -{# Render the body of a schema (properties, items, variants, etc.) #} -{% macro render_schema_body(node, depth, path) %} -{%- if depth < 10 -%} -{%- if node["$ref"] -%} - {# Reference only, already shown as type badge #} -{%- elif node.properties -%} - {%- set required_arr = node.required | default(value=[]) -%} -
    - Properties ({{ node.properties | length }}) -
    - {%- for prop_name, prop in node.properties -%} - {%- set is_required = prop_name in required_arr -%} - {{ self::render_property(name=prop_name, node=prop, required=is_required, depth=depth + 1, path=path ~ "." ~ prop_name) }} - {%- endfor -%} -
    -
    -{%- elif node.patternProperties -%} -
    - {%- for pattern, prop in node.patternProperties -%} -
    -
    - {# Convert known patterns to friendly type names - show as quoted string to indicate JSON string key #} - {# Note: patterns use single backslash in the parsed JSON value #} - {%- if pattern == "^\d+$" or pattern == "^[0-9]+$" or pattern == "^-?\d+$" or pattern == "^-?[0-9]+$" -%} - "<integer>" - {%- elif pattern == ".*" or pattern == "^.*$" -%} - "<string>" - {%- else -%} - {{ pattern }} - pattern - {%- endif -%} - → - {{ self::render_type_badge(node=prop) }} -
    - {%- if prop.description_html %}
    {{ prop.description_html | safe }}
    {% endif -%} - {{ self::render_schema_body(node=prop, depth=depth + 1, path=path ~ ".[key]") }} -
    - {%- endfor -%} -
    -{%- elif node.items -%} - {%- if node.items["$ref"] -%} - {# Already shown in type badge, no dropdown needed #} - {%- elif node.items.type and node.items.type is string -%} - {# Simple type (string, number, integer, boolean) - already shown in type badge #} - {%- else -%} - {# Complex item type needs dropdown #} -
    - Array Items -
    {{ self::render_schema(node=node.items, depth=depth + 1, path=path ~ "[]") }}
    -
    - {%- endif -%} -{%- elif node.prefixItems -%} - {# Check if homogeneous tuple - already shown as [T; N] in badge #} - {%- set first_type = node.prefixItems | first -%} - {%- set_global is_homogeneous = true -%} - {%- for item in node.prefixItems -%} - {%- if item.type is defined and first_type.type is defined -%} - {%- if item.type != first_type.type -%} - {%- set_global is_homogeneous = false -%} - {%- endif -%} - {%- else -%} - {# If either lacks a direct type (uses $ref, anyOf, etc.), not homogeneous #} - {%- set_global is_homogeneous = false -%} - {%- endif -%} - {%- endfor -%} - {%- if is_homogeneous and first_type.type -%} - {# Homogeneous tuple - already shown as [T; N] in badge, no dropdown needed #} - {%- else -%} - {# Heterogeneous tuple - show dropdown #} -
    - Tuple Items ({{ node.prefixItems | length }}) -
    - {%- for item in node.prefixItems -%} -
    [{{ loop.index0 }}]{{ self::render_schema(node=item, depth=depth + 1, path=path ~ "[" ~ loop.index0 ~ "]") }}
    - {%- endfor -%} -
    -
    - {%- endif -%} -{%- elif node.anyOf -%} - {# Check for wrapper type pattern first (detected in prepare.rs) #} - {%- if node._wrapper_type -%} - {# Wrapper type - render the inner type's body #} - {{ self::render_schema_body(node=node._wrapper_inner, depth=depth, path=path) }} - {# Check for Option pattern: anyOf with exactly 2 variants where one is null #} - {%- elif node.anyOf | length == 2 -%} - {%- set first = node.anyOf | first -%} - {%- set second = node.anyOf | last -%} - {%- if second.type and second.type == "null" -%} - {# Option - just render the non-null variant's body #} - {{ self::render_schema_body(node=first, depth=depth, path=path) }} - {%- elif first.type and first.type == "null" -%} - {# Option with null first - just render the non-null variant's body #} - {{ self::render_schema_body(node=second, depth=depth, path=path) }} - {%- else -%} - {# Check if all variants are string const (enum pattern) #} - {%- set_global is_string_enum = true -%} - {%- for variant in node.anyOf -%} - {%- if variant.type and variant.type == "string" and variant.const -%} - {# valid string const #} - {%- else -%} - {%- set_global is_string_enum = false -%} - {%- endif -%} - {%- endfor -%} - {# Render all anyOf variants using full schema rendering #} -
    - Enum variants ({{ node.anyOf | length }}) -
    - {%- for variant in node.anyOf -%} -
    {{ self::render_schema(node=variant, depth=depth + 1, path=path ~ ".anyOf[" ~ loop.index0 ~ "]") }}
    - {%- endfor -%} -
    -
    - {%- endif -%} - {%- else -%} - {# Render all anyOf variants using full schema rendering #} -
    - Enum variants ({{ node.anyOf | length }}) -
    - {%- for variant in node.anyOf -%} -
    {{ self::render_schema(node=variant, depth=depth + 1, path=path ~ ".anyOf[" ~ loop.index0 ~ "]") }}
    - {%- endfor -%} -
    -
    - {%- endif -%} -{%- elif node.oneOf -%} - {# Render all oneOf variants using full schema rendering #} -
    - Enum variants ({{ node.oneOf | length }}) -
    - {%- for variant in node.oneOf -%} -
    {{ self::render_schema(node=variant, depth=depth + 1, path=path ~ ".oneOf[" ~ loop.index0 ~ "]") }}
    - {%- endfor -%} -
    -
    -{%- elif node.allOf -%} -
    - All of ({{ node.allOf | length }} schemas) -
    - {%- for variant in node.allOf -%} -
    {{ self::render_schema(node=variant, depth=depth + 1, path=path ~ ".allOf[" ~ loop.index0 ~ "]") }}
    - {%- endfor -%} -
    -
    -{%- elif node.enum -%} - {%- set enum_count = node.enum | length -%} -
    - Enum variants ({{ enum_count }}) -
      - {%- for value in node.enum -%}
    • {{ value | json_encode() }}
    • {%- endfor -%} -
    -
    -{%- elif node.const -%} -
    Value: {{ node.const | json_encode() }}
    -{%- endif -%} -{%- if node.additionalProperties and node.additionalProperties is object -%} -
    - Additional Properties - {{ self::render_schema(node=node.additionalProperties, depth=depth + 1, path=path ~ ".[*]") }} -
    -{%- endif -%} -{%- endif -%} -{% endmacro render_schema_body %} - -{# Render a schema without property wrapper #} -{% macro render_schema(node, depth, path) %} -{%- if depth < 10 -%} -
    - {{ self::render_type_badge(node=node) }}{%- if node.description_html %}
    {{ node.description_html | safe }}
    {% endif -%} - {{ self::render_constraints(node=node) }} - {%- if node.default %}
    Default: {% if node._default_ref and schema["$defs"][node._default_ref] %}{{ node.default | json_encode() }}{% else %}{{ node.default | json_encode() }}{% endif %}
    {% endif -%} - {{ self::render_schema_body(node=node, depth=depth, path=path) }} -
    -{%- endif -%} -{% endmacro render_schema %} diff --git a/src/templates/mdx_base.md b/src/templates/mdx_base.md index 432b31e4..e7c0e6e3 100644 --- a/src/templates/mdx_base.md +++ b/src/templates/mdx_base.md @@ -8,10 +8,18 @@ import { Badge } from '@astrojs/starlight/components'; ## Configuration {% if schema.properties %} +{# First render required properties #} {% for prop_name, prop in schema.properties -%} -{%- set is_required = prop_name in required_set -%} -{{ macros::render_property(name=prop_name, node=prop, required=is_required, depth=0, path=prop_name) }} -{% endfor %} +{%- if prop_name in required_set -%} +{{ macros::render_property(name=prop_name, node=prop, required=true, depth=0, path=prop_name) }} +{% endif -%} +{%- endfor -%} +{# Then render optional properties #} +{% for prop_name, prop in schema.properties -%} +{%- if prop_name not in required_set -%} +{{ macros::render_property(name=prop_name, node=prop, required=false, depth=0, path=prop_name) }} +{% endif -%} +{%- endfor %} {% else %} *No configuration properties defined.* {% endif %} diff --git a/src/templates/mdx_macros.md b/src/templates/mdx_macros.md index 47032497..01efab00 100644 --- a/src/templates/mdx_macros.md +++ b/src/templates/mdx_macros.md @@ -1,18 +1,29 @@ -{# MDX Macros for Astro Starlight documentation generation #} -{# These macros mirror the HTML macro logic for consistent output #} +{# ============================================================================ #} +{# MDX Macros for Astro Starlight documentation generation #} +{# ============================================================================ #} +{# + Enum Pattern Reference (see ENUMS.md for full details): + - Pattern 1: Simple Unit Enums - oneOf with {type: "string", const: "Value"} + - Pattern 2: Unit Enum with Default - Pattern 1 + "default" field + - Pattern 3: Mixed Enum - oneOf with unit variants + tuple/object variants + - Pattern 4a-d: Untagged Enums - anyOf with various combinations ($ref, tuple, array) + - Pattern 5: Internally Tagged - oneOf with discriminator field (const) + properties + - Pattern 6: Internally Tagged + Flatten - oneOf with properties + $ref at same level + - Pattern 7: Externally Tagged - oneOf with variant name as property key + - Pattern 8: Untagged Hybrid - anyOf mixing const strings + $ref + - Pattern 9: Untagged with Nulls - anyOf with multiple {type: "null"} variants + - Pattern 10: Generic Enum - anyOf with {additionalProperties: T} + T + - Pattern 11: Nullable Optional - anyOf with $ref + {type: "null"} + default +#} + +{# ============================================================================ #} +{# SECTION 1: Type Badge Rendering #} +{# ============================================================================ #} +{# Render the type badge for a schema - outputs inline code or links #} +{# Pattern 6: When node has BOTH type AND $ref (flattened config), prioritize type #} -{# Render the type badge for a schema - outputs inline code or links #} {% macro render_type_badge(node) %} -{%- if node["$ref"] -%} - {%- set ref_name = node["$ref"] | replace(from="#/$defs/", to="") -%} - {%- set display = display_names[ref_name] | default(value=ref_name) -%} - {%- if schema["$defs"][ref_name] -%} - {%- set ref_def = schema["$defs"][ref_name] -%} -[`{{ display }}`](#{{ ref_name | lower }}){% if ref_def._wrapper_inner %} {{ self::render_type_badge(node=ref_def._wrapper_inner) }}{% endif -%} - {%- else -%} -`$ref` - {%- endif -%} -{%- elif node.type -%} +{%- if node.type -%} {%- if node.type is string -%} {%- if node.type == "array" and node.prefixItems -%} {# Check if all prefixItems have the same type (homogeneous tuple) #} @@ -28,7 +39,7 @@ {%- endif -%} {%- endfor -%} {%- if is_homogeneous and first_type.type -%} -`array` {% if first_type.type == "number" %}`[float; {{ node.prefixItems | length }}]`{% else %}`[{{ first_type.type }}; {{ node.prefixItems | length }}]`{% endif %} +`array` `[{% if first_type.format %}{{ first_type.format }}{% else %}{{ first_type.type }}{% endif %}; {{ node.prefixItems | length }}]` {%- else -%} `array` `tuple` {%- endif -%} @@ -46,18 +57,19 @@ {%- endif -%} {%- endif -%} {%- elif node.anyOf -%} - {# Check for wrapper type pattern first #} + {# Pattern 10: Wrapper type (detected in prepare.rs) #} {%- if node._wrapper_type -%} {{ self::render_type_badge(node=node._wrapper_inner) }} {%- elif node.anyOf | length == 2 -%} {%- set first = node.anyOf | first -%} {%- set second = node.anyOf | last -%} + {# Pattern 11: Nullable Optional - anyOf with T + null #} {%- if second.type and second.type == "null" -%} {{ self::render_type_badge(node=first) }} {%- elif first.type and first.type == "null" -%} {{ self::render_type_badge(node=second) }} {%- else -%} - {# Check if all variants are string const (enum pattern) #} + {# Pattern 8: Check if all variants are string const (untagged hybrid) #} {%- set_global is_string_enum = true -%} {%- for variant in node.anyOf -%} {%- if variant.type and variant.type == "string" and variant.const -%} @@ -72,7 +84,7 @@ {%- endif -%} {%- endif -%} {%- else -%} - {# Check if all variants are string const (enum pattern) #} + {# Pattern 4a-d, 8, 9: Untagged enums with 3+ variants #} {%- set_global is_string_enum = true -%} {%- for variant in node.anyOf -%} {%- if variant.type and variant.type == "string" and variant.const -%} @@ -87,11 +99,13 @@ {%- endif -%} {%- endif -%} {%- elif node.oneOf -%} - {# Check if all variants are string const (enum pattern) #} + {# Pattern 1-3, 5-7: Tagged enums using oneOf #} {%- set_global is_string_enum = true -%} {%- for variant in node.oneOf -%} + {# Pattern 1-2: Simple unit enum with string const #} {%- if variant.type and variant.type == "string" and variant.const -%} {%- else -%} + {# Pattern 3, 5, 6, 7: Complex variants (objects, refs, etc.) #} {%- set_global is_string_enum = false -%} {%- endif -%} {%- endfor -%} @@ -102,6 +116,16 @@ {%- endif -%} {%- elif node.allOf -%} `allOf` +{%- elif node["$ref"] -%} + {# Reference type (no inline type field) #} + {%- set ref_name = node["$ref"] | replace(from="#/$defs/", to="") -%} + {%- set display = display_names[ref_name] | default(value=ref_name) -%} + {%- if schema["$defs"][ref_name] -%} + {%- set ref_def = schema["$defs"][ref_name] -%} +[`{{ display }}`](#{{ ref_name | lower }}){% if ref_def._wrapper_inner %} {{ self::render_type_badge(node=ref_def._wrapper_inner) }}{% endif -%} + {%- else -%} +`$ref` + {%- endif -%} {%- elif node.const -%} `const` {%- elif node.enum -%} @@ -109,7 +133,11 @@ {%- endif -%} {% endmacro render_type_badge %} -{# Render constraints like min, max, pattern, format #} +{# ============================================================================ #} +{# SECTION 2: Constraint Rendering #} +{# ============================================================================ #} +{# Render constraints like min, max, pattern, format #} + {% macro render_constraints(node) %} {# Check if this is a homogeneous tuple - skip minItems/maxItems if so #} {%- set_global skip_item_constraints = false -%} @@ -143,7 +171,11 @@ {%- endif -%} {% endmacro render_constraints %} -{# Render the body of a schema (properties, items, variants, etc.) #} +{# ============================================================================ #} +{# SECTION 3: Schema Body Rendering #} +{# ============================================================================ #} +{# Render the body of a schema (properties, items, variants, etc.) #} + {% macro render_schema_body(node, depth, path) %} {%- if depth < 10 -%} {%- if node["$ref"] -%} @@ -151,13 +183,23 @@ {%- elif node.properties -%} {%- set required_arr = node.required | default(value=[]) -%} -
    +
    Properties ({{ node.properties | length }}) +{# First render required properties #} {% for prop_name, prop in node.properties -%} -{%- set is_required = prop_name in required_arr -%} +{%- if prop_name in required_arr -%} +{%- set is_required = true -%} {{ self::render_nested_property(name=prop_name, node=prop, required=is_required, depth=depth + 1, path=path ~ "." ~ prop_name) }} -{% endfor %} +{% endif -%} +{%- endfor -%} +{# Then render optional properties #} +{% for prop_name, prop in node.properties -%} +{%- if prop_name not in required_arr -%} +{%- set is_required = false -%} +{{ self::render_nested_property(name=prop_name, node=prop, required=is_required, depth=depth + 1, path=path ~ "." ~ prop_name) }} +{% endif -%} +{%- endfor %}
    {%- elif node.patternProperties -%} @@ -181,7 +223,7 @@ {# Simple type - already shown in type badge #} {%- else -%} -
    +
    Array Items {{ self::render_schema(node=node.items, depth=depth + 1, path=path ~ "[]") }} @@ -204,7 +246,7 @@ {# Homogeneous tuple - already shown as [T; N] in badge #} {%- else -%} -
    +
    Tuple Items ({{ node.prefixItems | length }}) {% for item in node.prefixItems %} @@ -213,51 +255,55 @@
    {%- endif -%} {%- elif node.anyOf -%} - {# Check for wrapper type pattern first #} + {# Pattern 10: Wrapper type (detected in prepare.rs) #} {%- if node._wrapper_type -%} {{ self::render_schema_body(node=node._wrapper_inner, depth=depth, path=path) }} {%- elif node.anyOf | length == 2 -%} {%- set first = node.anyOf | first -%} {%- set second = node.anyOf | last -%} + {# Pattern 11: Nullable Optional - unwrap the non-null variant #} {%- if second.type and second.type == "null" -%} {{ self::render_schema_body(node=first, depth=depth, path=path) }} {%- elif first.type and first.type == "null" -%} {{ self::render_schema_body(node=second, depth=depth, path=path) }} {%- else -%} + {# Pattern 4a-d, 8: Two non-null variants #} -
    +
    Enum variants ({{ node.anyOf | length }}) {% for variant in node.anyOf %} --- -{{ self::render_schema(node=variant, depth=depth + 1, path=path ~ ".anyOf[" ~ loop.index0 ~ "]") }} +{{ self::render_enum_variant(node=variant, depth=depth + 1, path=path ~ ".anyOf[" ~ loop.index0 ~ "]") }} {% endfor %}
    {%- endif -%} {%- else -%} + {# Pattern 4a-d, 8, 9: Untagged enums with 3+ variants #} -
    +
    Enum variants ({{ node.anyOf | length }}) {% for variant in node.anyOf %} --- -{{ self::render_schema(node=variant, depth=depth + 1, path=path ~ ".anyOf[" ~ loop.index0 ~ "]") }} +{{ self::render_enum_variant(node=variant, depth=depth + 1, path=path ~ ".anyOf[" ~ loop.index0 ~ "]") }} {% endfor %}
    {%- endif -%} {%- elif node.oneOf -%} +{# Pattern 1-3, 5-7: Tagged enums using oneOf #} -
    +
    Enum variants ({{ node.oneOf | length }}) {% for variant in node.oneOf %} --- -{{ self::render_schema(node=variant, depth=depth + 1, path=path ~ ".oneOf[" ~ loop.index0 ~ "]") }} +{{ self::render_enum_variant(node=variant, depth=depth + 1, path=path ~ ".oneOf[" ~ loop.index0 ~ "]") }} {% endfor %}
    {%- elif node.allOf -%} -
    +
    All of ({{ node.allOf | length }} schemas) {% for variant in node.allOf %} @@ -267,7 +313,7 @@
    {%- elif node.enum -%} -
    +
    Enum variants ({{ node.enum | length }}) {% for value in node.enum %}- `{{ value | json_encode() }}` @@ -279,7 +325,7 @@ {%- endif -%} {%- if node.additionalProperties and node.additionalProperties is object -%} -
    +
    Additional Properties {{ self::render_schema(node=node.additionalProperties, depth=depth + 1, path=path ~ ".[*]") }} @@ -288,15 +334,25 @@ {%- endif -%} {% endmacro render_schema_body %} -{# Render a schema without property wrapper #} +{# ============================================================================ #} +{# SECTION 4: Schema Rendering #} +{# ============================================================================ #} +{# Render a schema without property wrapper #} + {% macro render_schema(node, depth, path) %} {%- if depth < 10 -%} -{# Skip type badge for documented const variants - the value is shown below #} +{# For const variants with description, show description then value on separate lines #} {%- if node.const and node.description -%} {{ node.description | mdx_escape }} + +**Value:** `{{ node.const | json_encode() }}` +{%- elif node.const -%} +**Value:** `{{ node.const | json_encode() }}` {%- else -%} -{{ self::render_type_badge(node=node) }}{% if node.description %} - {{ node.description | mdx_escape }}{% endif %} -{%- endif -%} +{{ self::render_type_badge(node=node) }} +{% if node.description %} +{{ node.description | mdx_escape }} +{% endif %} {{ self::render_constraints(node=node) }} {%- if node.default %} @@ -304,9 +360,307 @@ {% endif -%} {{ self::render_schema_body(node=node, depth=depth, path=path) }} {%- endif -%} +{%- endif -%} {% endmacro render_schema %} -{# Render a nested property (used within details blocks) #} +{# ============================================================================ #} +{# SECTION 5: Enum Variant Rendering #} +{# ============================================================================ #} +{# Render an enum variant - like render_schema but uses render_enum_variant_body #} +{# for flat property display. Uses exhaustive fallback chain for variant titles. #} +{# #} +{# Title extraction priority (see ENUMS.md for pattern details): #} +{# 1. node.title (explicit #[schemars(title = "...")]) #} +{# 2. node.const (Pattern 1, 2, 3 unit variants, Pattern 9 hybrid) #} +{# 3. properties..const (Pattern 5, 6, 8 discriminator field) #} +{# 4. required[0] when additionalProperties=false (Pattern 7 externally tagged) #} +{# 5. $ref type name (Pattern 4, 9, 10 reference types) #} +{# 6. Type-based fallback (array, tuple, map, primitives) #} +{# ============================================================================ #} + +{% macro render_enum_variant(node, depth, path) %} +{%- if depth < 10 -%} +{# Extract variant name using exhaustive fallback chain #} +{%- set_global variant_name = "" -%} + +{# Priority 1: Explicit title #} +{%- if node.title -%} + {%- set_global variant_name = node.title -%} + +{# Priority 2: Const value (Pattern 1, 2, 3 unit variants, Pattern 9) #} +{%- elif node.const -%} + {%- set_global variant_name = node.const -%} + +{# Priority 3 & 4: Properties-based extraction #} +{%- elif node.properties -%} + {# Priority 3: Discriminator const from properties (Pattern 5, 6, 8) #} + {%- for prop_name, prop in node.properties -%} + {%- if prop.const and variant_name == "" -%} + {%- set_global variant_name = prop.const -%} + {%- endif -%} + {%- endfor -%} + {# Priority 4: Externally tagged - property key (Pattern 7) #} + {%- if variant_name == "" and node.additionalProperties is defined and node.additionalProperties == false -%} + {%- if node.required and node.required | length > 0 -%} + {%- set_global variant_name = node.required | first -%} + {%- endif -%} + {%- endif -%} + +{# Priority 5: $ref type name (Pattern 4, 9, 10) #} +{%- elif node["$ref"] -%} + {%- set ref_name = node["$ref"] | replace(from="#/$defs/", to="") -%} + {%- set_global variant_name = display_names[ref_name] | default(value=ref_name) -%} + +{# Priority 6: Type-based fallback #} +{%- elif node.type -%} + {%- if node.type is string -%} + {%- if node.type == "array" -%} + {%- if node.items and node.items["$ref"] -%} + {%- set item_ref = node.items["$ref"] | replace(from="#/$defs/", to="") -%} + {%- set item_display = display_names[item_ref] | default(value=item_ref) -%} + {%- set_global variant_name = item_display ~ " Array" -%} + {%- elif node.prefixItems -%} + {%- set_global variant_name = "Tuple" -%} + {%- else -%} + {%- set_global variant_name = "Array" -%} + {%- endif -%} + {%- elif node.type == "object" and node.additionalProperties -%} + {%- set_global variant_name = "Map" -%} + {%- else -%} + {%- set_global variant_name = node.type | capitalize -%} + {%- endif -%} + {%- endif -%} +{%- endif -%} + +{# Render heading if we have a variant name #} +{%- if variant_name %} +#### {{ variant_name }} +{% endif -%} + +{# Render description #} +{% if node.description %} +{{ node.description | mdx_escape }} +{% endif %} + +{# Render value based on variant type #} +{# First check for Pattern 7: Externally Tagged (single property with additionalProperties: false) #} +{# These are handled specially in render_enum_variant_body, so skip generic value here #} +{%- set_global is_pattern7 = false -%} +{%- if node.properties -%} + {%- set props_count = node.properties | length -%} + {%- if props_count == 1 and node.additionalProperties is defined and node.additionalProperties == false -%} + {%- set_global is_pattern7 = true -%} + {%- endif -%} +{%- endif -%} +{%- if node.const -%} +**Value:** `{{ node.const | json_encode() }}` +{%- elif not is_pattern7 and (node["$ref"] or node.type or node.anyOf or node.oneOf or node.allOf) %} +**Value:** {{ self::render_type_badge(node=node) }} +{%- endif %} + +{{ self::render_constraints(node=node) }} +{%- if node.default %} + +**Default:** {% if node._default_ref and schema["$defs"][node._default_ref] %}[`{{ node.default | json_encode() }}`](#{{ node._default_ref | lower }}){% else %}`{{ node.default | json_encode() }}`{% endif %} +{% endif -%} +{{ self::render_enum_variant_body(node=node, depth=depth, path=path) }} +{%- endif -%} +{% endmacro render_enum_variant %} + +{# ============================================================================ #} +{# SECTION 6: Enum Variant Body Rendering #} +{# ============================================================================ #} +{# Render the body of an enum variant - properties are shown directly without #} +{# details wrapper, required first. #} +{# Handles Pattern 3 (mixed), Pattern 5 (internally tagged), #} +{# Pattern 6 (internally tagged + flatten), Pattern 7 (externally tagged) #} + +{% macro render_enum_variant_body(node, depth, path) %} +{%- if depth < 10 -%} +{%- if node.properties -%} + {# Check for Pattern 7: Externally Tagged Enum (single property with additionalProperties: false) #} + {%- set props_count = node.properties | length -%} + {%- if props_count == 1 and node.additionalProperties is defined and node.additionalProperties == false -%} + {# Pattern 7: Externally Tagged - render variant name and value inline #} + {%- for prop_name, prop in node.properties -%} + +**Value:** `{{ prop_name }}` → {{ self::render_type_badge(node=prop) }} + {%- endfor -%} + {%- else -%} + {# Pattern 5, 6: Object variants with properties (internally tagged) #} + {# Pattern 6: Handle properties first - this covers cases where both properties and $ref exist #} + {# Skip properties with const values (discriminator fields) - already shown as variant heading #} + {%- set required_arr = node.required | default(value=[]) -%} + +{# First render required properties (skip discriminator fields with const) #} +{% for prop_name, prop in node.properties -%} +{%- if prop_name in required_arr and not prop.const -%} +{%- set is_required = true -%} +{{ self::render_nested_property(name=prop_name, node=prop, required=is_required, depth=depth + 1, path=path ~ "." ~ prop_name) }} +{% endif -%} +{%- endfor -%} +{# Then render optional properties (skip discriminator fields with const) #} +{% for prop_name, prop in node.properties -%} +{%- if prop_name not in required_arr and not prop.const -%} +{%- set is_required = false -%} +{{ self::render_nested_property(name=prop_name, node=prop, required=is_required, depth=depth + 1, path=path ~ "." ~ prop_name) }} +{% endif -%} +{%- endfor -%} + {%- endif -%} +{# Pattern 6: If node has both properties AND $ref, also render the referenced type's properties #} +{%- if node["$ref"] -%} + {%- set ref_name = node["$ref"] | replace(from="#/$defs/", to="") -%} + {%- if schema["$defs"][ref_name] -%} + {%- set ref_def = schema["$defs"][ref_name] -%} + {%- if ref_def.properties -%} + {%- set ref_required_arr = ref_def.required | default(value=[]) -%} +{# First render required properties from referenced type #} +{% for prop_name, prop in ref_def.properties -%} +{%- if prop_name in ref_required_arr -%} +{%- set is_required = true -%} +{{ self::render_nested_property(name=prop_name, node=prop, required=is_required, depth=depth + 1, path=path ~ "." ~ prop_name) }} +{% endif -%} +{%- endfor -%} +{# Then render optional properties from referenced type #} +{% for prop_name, prop in ref_def.properties -%} +{%- if prop_name not in ref_required_arr -%} +{%- set is_required = false -%} +{{ self::render_nested_property(name=prop_name, node=prop, required=is_required, depth=depth + 1, path=path ~ "." ~ prop_name) }} +{% endif -%} +{%- endfor -%} + {%- endif -%} + {%- endif -%} +{%- endif -%} +{%- elif node["$ref"] -%} + {# Reference only, already shown as type badge #} +{%- elif node.patternProperties -%} + +{% for pattern, prop in node.patternProperties %} +{% if pattern == "^\d+$" or pattern == "^[0-9]+$" or pattern == "^-?\d+$" or pattern == "^-?[0-9]+$" -%} +**Key:** `""` **→** {{ self::render_type_badge(node=prop) }} +{% elif pattern == ".*" or pattern == "^.*$" -%} +**Key:** `""` **→** {{ self::render_type_badge(node=prop) }} +{% else -%} +**Pattern:** `{{ pattern }}` **→** {{ self::render_type_badge(node=prop) }} +{% endif %} +{% if prop.description %}{{ prop.description | mdx_escape }}{% endif %} +{{ self::render_enum_variant_body(node=prop, depth=depth + 1, path=path ~ ".[key]") }} +{% endfor %} +{%- elif node.items -%} + {%- if node.items["$ref"] -%} + {# Already shown in type badge #} + {%- elif node.items.type and node.items.type is string -%} + {# Simple type - already shown in type badge #} + {%- else -%} + +
    +Array Items + +{{ self::render_enum_variant(node=node.items, depth=depth + 1, path=path ~ "[]") }} +
    + {%- endif -%} +{%- elif node.prefixItems -%} + {%- set first_type = node.prefixItems | first -%} + {%- set_global is_homogeneous = true -%} + {%- for item in node.prefixItems -%} + {%- if item.type is defined and first_type.type is defined -%} + {%- if item.type != first_type.type -%} + {%- set_global is_homogeneous = false -%} + {%- endif -%} + {%- else -%} + {%- set_global is_homogeneous = false -%} + {%- endif -%} + {%- endfor -%} + {%- if is_homogeneous and first_type.type -%} + {# Homogeneous tuple - already shown as [T; N] in badge #} + {%- else -%} + +
    +Tuple Items ({{ node.prefixItems | length }}) + +{% for item in node.prefixItems %} +**[{{ loop.index0 }}]** {{ self::render_enum_variant(node=item, depth=depth + 1, path=path ~ "[" ~ loop.index0 ~ "]") }} +{% endfor %} +
    + {%- endif -%} +{%- elif node.anyOf -%} + {%- if node._wrapper_type -%} +{{ self::render_enum_variant_body(node=node._wrapper_inner, depth=depth, path=path) }} + {%- elif node.anyOf | length == 2 -%} + {%- set first = node.anyOf | first -%} + {%- set second = node.anyOf | last -%} + {%- if second.type and second.type == "null" -%} +{{ self::render_enum_variant_body(node=first, depth=depth, path=path) }} + {%- elif first.type and first.type == "null" -%} +{{ self::render_enum_variant_body(node=second, depth=depth, path=path) }} + {%- else -%} + +
    +Enum variants ({{ node.anyOf | length }}) + +{% for variant in node.anyOf %} +--- +{{ self::render_enum_variant(node=variant, depth=depth + 1, path=path ~ ".anyOf[" ~ loop.index0 ~ "]") }} +{% endfor %} +
    + {%- endif -%} + {%- else -%} + +
    +Enum variants ({{ node.anyOf | length }}) + +{% for variant in node.anyOf %} +--- +{{ self::render_enum_variant(node=variant, depth=depth + 1, path=path ~ ".anyOf[" ~ loop.index0 ~ "]") }} +{% endfor %} +
    + {%- endif -%} +{%- elif node.oneOf -%} + +
    +Enum variants ({{ node.oneOf | length }}) + +{% for variant in node.oneOf %} +--- +{{ self::render_enum_variant(node=variant, depth=depth + 1, path=path ~ ".oneOf[" ~ loop.index0 ~ "]") }} +{% endfor %} +
    +{%- elif node.allOf -%} + +
    +All of ({{ node.allOf | length }} schemas) + +{% for variant in node.allOf %} +--- +{{ self::render_enum_variant(node=variant, depth=depth + 1, path=path ~ ".allOf[" ~ loop.index0 ~ "]") }} +{% endfor %} +
    +{%- elif node.enum -%} + +
    +Enum variants ({{ node.enum | length }}) + +{% for value in node.enum %}- `{{ value | json_encode() }}` +{% endfor %} +
    +{# Note: node.const is NOT handled here - it's already rendered in render_enum_variant #} +{%- endif -%} +{%- if node.additionalProperties and node.additionalProperties is object -%} + +
    +Additional Properties + +{{ self::render_enum_variant(node=node.additionalProperties, depth=depth + 1, path=path ~ ".[*]") }} +
    +{%- endif -%} +{%- endif -%} +{% endmacro render_enum_variant_body %} + +{# ============================================================================ #} +{# SECTION 7: Property Rendering #} +{# ============================================================================ #} +{# Render a nested property (used within details blocks) #} + {% macro render_nested_property(name, node, required, depth, path) %} {%- if depth < 10 -%} {%- set anchor = path | lower | replace(from=".", to="-") -%} @@ -324,7 +678,8 @@ {%- endif -%} {% endmacro render_nested_property %} -{# Render a top-level property as H3 #} +{# Render a top-level property as H3 #} + {% macro render_property(name, node, required, depth, path) %} {%- if depth < 10 -%} {%- set anchor = path | lower | replace(from=".", to="-") -%} @@ -345,7 +700,11 @@ {%- endif -%} {% endmacro render_property %} -{# Render usages section for a type definition #} +{# ============================================================================ #} +{# SECTION 8: Definition & Usage Rendering #} +{# ============================================================================ #} +{# Render usages section for a type definition #} + {% macro render_usages(def) %} {%- if def._usages and (def._usages.config_usages | length > 0 or def._usages.type_references | length > 0) -%} @@ -365,13 +724,12 @@ {%- endif -%} {% endmacro render_usages %} -{# Render a type definition as H3 #} +{# Render a type definition as H3 #} + {% macro render_definition(def_name, def) %} {%- set anchor = def_name | lower | replace(from=".", to="-") -%} ### {{ def._display_name | default(value=def_name) }} {{"{"}}#{{ anchor }}{{"}"}} -{{ self::render_type_badge(node=def) }} - {% if def.description %}{{ def.description | mdx_escape }}{% endif %} {{ self::render_constraints(node=def) }} {{ self::render_schema_body(node=def, depth=0, path=def_name) }} diff --git a/src/templates/style.css b/src/templates/style.css deleted file mode 100644 index 7400c637..00000000 --- a/src/templates/style.css +++ /dev/null @@ -1,1216 +0,0 @@ -/* CSS Custom Properties for theming */ -:root { - --bg-primary: #ffffff; - --bg-secondary: #f8f9fa; - --bg-tertiary: #e9ecef; - --text-primary: #212529; - --text-secondary: #6c757d; - --text-muted: #adb5bd; - --accent: #0d6efd; - --accent-hover: #0b5ed7; - --border: #dee2e6; - --border-light: #e9ecef; - --code-bg: #f1f3f5; - --code-text: #e83e8c; - --description-bg: #f8f9fa; - --description-border: #0d6efd; - --success: #198754; - --warning: #ffc107; - --danger: #dc3545; - --highlight: #fff3cd; - --shadow: rgba(0, 0, 0, 0.1); - --font-sans: - -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", - Arial, sans-serif; - --font-mono: - SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", - "Courier New", monospace; -} - -/* Dark mode - follows system preference */ -@media (prefers-color-scheme: dark) { - :root { - --bg-primary: #1a1d21; - --bg-secondary: #22262b; - --bg-tertiary: #2c3137; - --text-primary: #e9ecef; - --text-secondary: #adb5bd; - --text-muted: #6c757d; - --accent: #6ea8fe; - --accent-hover: #8bb9fe; - --border: #3d4349; - --border-light: #2c3137; - --code-bg: #2c3137; - --code-text: #f8a4c4; - --description-bg: #22262b; - --description-border: #6ea8fe; - --highlight: #3d3520; - --shadow: rgba(0, 0, 0, 0.3); - } -} - -/* Reset and base styles */ -*, -*::before, -*::after { - box-sizing: border-box; -} - -html { - scroll-behavior: smooth; - font-size: 16px; - scroll-padding-top: 80px; -} - -body { - margin: 0; - padding: 0; - font-family: var(--font-sans); - font-size: 1rem; - line-height: 1.6; - color: var(--text-primary); - background-color: var(--bg-primary); -} - -/* Header */ -.header { - position: sticky; - top: 0; - z-index: 100; - background-color: var(--bg-secondary); - border-bottom: 1px solid var(--border); - padding: 1rem; - box-shadow: 0 2px 4px var(--shadow); -} - -.header-content { - max-width: 1400px; - margin: 0 auto; -} - -.header h1 { - margin: 0 0 0.5rem 0; - font-size: 1.5rem; - font-weight: 600; -} - -/* Search */ -.search-container { - position: relative; - max-width: 400px; -} - -#search { - width: 100%; - padding: 0.5rem 1rem; - font-size: 0.9rem; - border: 1px solid var(--border); - border-radius: 6px; - background-color: var(--bg-primary); - color: var(--text-primary); - outline: none; - transition: - border-color 0.15s, - box-shadow 0.15s; -} - -#search:focus { - border-color: var(--accent); - box-shadow: 0 0 0 3px rgba(13, 110, 253, 0.15); -} - -#search::placeholder { - color: var(--text-muted); -} - -.search-results { - display: none; - position: absolute; - top: 100%; - left: 0; - right: 0; - background: var(--bg-primary); - border: 1px solid var(--border); - border-radius: 6px; - margin-top: 4px; - max-height: 300px; - overflow-y: auto; - box-shadow: 0 4px 12px var(--shadow); - z-index: 1000; -} - -.search-results.active { - display: block; -} - -.search-result-item { - display: flex; - align-items: center; - gap: 0.5rem; - padding: 0.5rem 1rem; - text-decoration: none; - color: var(--text-primary); - border-bottom: 1px solid var(--border-light); - transition: background-color 0.15s; -} - -.search-result-item:last-child { - border-bottom: none; -} - -.search-result-item:hover { - background-color: var(--bg-secondary); -} - -.search-result-item.no-results { - color: var(--text-secondary); - font-style: italic; -} - -.result-name { - font-weight: 500; -} - -.result-path { - color: var(--text-secondary); - font-size: 0.85rem; - flex: 1; -} - -.result-type { - font-size: 0.75rem; - padding: 0.125rem 0.375rem; - background: var(--bg-tertiary); - border-radius: 3px; - color: var(--text-secondary); -} - -/* Layout */ -.layout { - display: grid; - grid-template-columns: 1fr; - min-height: calc(100vh - 120px); -} - -@media (min-width: 768px) { - .layout { - grid-template-columns: 260px 1fr; - } -} - -@media (min-width: 1200px) { - .layout { - grid-template-columns: 280px 1fr; - } -} - -/* Sidebar */ -.sidebar { - background-color: var(--bg-secondary); - border-right: 1px solid var(--border); - padding: 1rem; - overflow-y: auto; - display: none; -} - -@media (min-width: 768px) { - .sidebar { - display: block; - position: sticky; - top: 80px; - height: calc(100vh - 80px); - } -} - -.sidebar.open { - display: block; - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - z-index: 200; - padding-top: 60px; -} - -.sidebar-header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 1rem; -} - -.sidebar-header h2 { - margin: 0; - font-size: 1rem; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.05em; - color: var(--text-secondary); -} - -.sidebar-toggle { - display: block; - padding: 0.5rem; - background: none; - border: none; - cursor: pointer; -} - -@media (min-width: 768px) { - .sidebar-toggle { - display: none; - } -} - -.sidebar-toggle span { - display: block; - width: 20px; - height: 2px; - background: var(--text-primary); - margin: 4px 0; -} - -.nav-list { - list-style: none; - margin: 0; - padding: 0; -} - -.nav-link { - display: block; - padding: 0.375rem 0.5rem; - color: var(--text-primary); - text-decoration: none; - border-radius: 4px; - font-size: 0.9rem; - transition: background-color 0.15s; -} - -.nav-link:hover { - background-color: var(--bg-tertiary); -} - -/* Sidebar sections */ -.sidebar-section { - margin-bottom: 1.5rem; -} - -.sidebar-section-title { - font-size: 0.7rem; - font-weight: 600; - text-transform: uppercase; - letter-spacing: 0.05em; - color: var(--text-muted); - margin: 0 0 0.5rem 0.5rem; -} - -.outline-list { - border-bottom: 1px solid var(--border); - padding-bottom: 1rem; - margin-bottom: 0.5rem; -} - -/* Hierarchical outline tree */ -.outline-item { - position: relative; -} - -.outline-children { - list-style: none; - margin: 0; - padding-left: 0.75rem; - border-left: 1px solid var(--border-light); - margin-left: 0.5rem; -} - -.outline-item.depth-1 > a.nav-link, -.outline-item.depth-1 > details > summary .nav-link { - font-size: 0.8rem; - color: var(--text-secondary); -} - -.outline-item.depth-2 > a.nav-link, -.outline-item.depth-2 > details > summary .nav-link { - font-size: 0.75rem; - color: var(--text-muted); -} - -/* Collapsible outline items */ -.outline-item details { - margin: 0; -} - -.outline-item details > summary { - list-style: none; - cursor: pointer; - display: flex; - align-items: center; - gap: 0.25rem; -} - -.outline-item details > summary::-webkit-details-marker { - display: none; -} - -/* Custom expand/collapse indicator */ -.outline-item details > summary::before { - content: "▶"; - font-size: 0.5rem; - color: var(--text-muted); - transition: transform 0.15s ease; - flex-shrink: 0; - width: 0.75rem; -} - -.outline-item details[open] > summary::before { - transform: rotate(90deg); -} - -/* Ensure link inside summary works correctly */ -.outline-item details > summary .nav-link { - flex: 1; -} - -/* Leaf items (no children) - add spacer to match expand icon width */ -.outline-item > a.nav-link { - display: flex; - align-items: center; - gap: 0.25rem; /* Same gap as expandable items */ -} - -.outline-item > a.nav-link::before { - content: ""; - width: 0.75rem; /* Same width as expand icon */ - flex-shrink: 0; -} - -/* Mobile sidebar toggle button in header */ -@media (max-width: 767px) { - .header-content { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: 1rem; - } - - .header h1 { - flex: 1; - } - - .search-container { - order: 3; - width: 100%; - max-width: none; - } -} - -/* Main content */ -.main-content { - padding: 1.5rem; - max-width: 900px; -} - -@media (min-width: 1200px) { - .main-content { - padding: 2rem; - } -} - -.schema-section { - margin-bottom: 3rem; -} - -.schema-section > h2 { - font-size: 1.5rem; - font-weight: 600; - margin: 0 0 1.5rem 0; - padding-bottom: 0.5rem; - border-bottom: 2px solid var(--accent); -} - -/* Definition */ -.definition { - margin-bottom: 2rem; - padding: 1.5rem; - background-color: var(--bg-secondary); - border-radius: 8px; - border: 1px solid var(--border); - scroll-margin-top: 100px; - transition: box-shadow 0.3s; -} - -.definition.highlight { - box-shadow: 0 0 0 3px var(--accent); -} - -.definition-name { - margin: 0 0 0.75rem 0; - font-size: 1.25rem; - font-weight: 600; - color: var(--accent); -} - -/* Property */ -.property { - padding: 1rem 0; - border-bottom: 1px solid var(--border-light); - scroll-margin-top: 100px; -} - -.property:last-child { - border-bottom: none; -} - -.property.highlight { - background-color: var(--highlight); - margin: 0 -1rem; - padding: 1rem; - border-radius: 4px; -} - -.property-header { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: 0.5rem; - margin-bottom: 0.5rem; -} - -.property-name { - font-family: var(--font-mono); - font-size: 1rem; - font-weight: 600; - color: var(--text-primary); - background: none; - padding: 0; -} - -.property-name.pattern { - color: var(--code-text); -} - -/* Badges */ -.badge { - display: inline-block; - padding: 0.125rem 0.5rem; - font-size: 0.7rem; - font-weight: 500; - text-transform: uppercase; - letter-spacing: 0.025em; - border-radius: 3px; - margin-left: 0.25rem; -} - -.badge:first-child { - margin-left: 0; -} - -.badge.required { - background-color: var(--danger); - color: white; -} - -.badge.deprecated { - background-color: var(--warning); - color: #000; -} - -.badge.pattern { - background-color: var(--accent); - color: white; -} - -/* Map key styling for patternProperties */ -.map-key { - font-family: var(--font-mono); - font-size: 0.95rem; - color: var(--text-primary); -} - -.map-key .key-type { - color: var(--accent); - font-weight: 500; -} - -.map-arrow { - color: var(--text-muted); - margin: 0 0.5rem; -} - -.badge.optional { - background-color: #6c757d; - color: white; -} - -/* Type badges */ -.type-badge { - display: inline-block; - padding: 0.125rem 0.5rem; - font-size: 0.75rem; - font-weight: 500; - border-radius: 3px; - background-color: var(--bg-tertiary); - color: var(--text-secondary); - margin-left: 0.25rem; -} - -.type-badge:first-child { - margin-left: 0; -} - -/* Primitive types */ -.type-badge.type-string { - background-color: #198754; - color: white; -} -.type-badge.type-number { - background-color: #0d6efd; - color: white; -} -.type-badge.type-integer { - background-color: #0a58ca; - color: white; -} -.type-badge.type-float { - background-color: #0d6efd; - color: white; -} -.type-badge.type-boolean { - background-color: #fd7e14; - color: white; -} -.type-badge.type-null { - background-color: #6c757d; - color: white; -} - -/* Complex types */ -.type-badge.type-object { - background-color: #6f42c1; - color: white; -} -.type-badge.type-array { - background-color: #0891b2; - color: white; -} - -/* Composition types */ -.type-badge.type-enum { - background-color: #d63384; - color: white; -} -.type-badge.type-union { - background-color: #6610f2; - color: white; -} -.type-badge.type-const { - background-color: #495057; - color: white; -} - -.type-ref { - display: inline-block; - padding: 0.125rem 0.5rem; - font-size: 0.75rem; - font-weight: 500; - border-radius: 3px; - background-color: #6f42c1; - color: white; - text-decoration: none; - transition: background-color 0.15s; - margin-left: 0.25rem; -} - -.type-ref:first-child { - margin-left: 0; -} - -.type-ref:hover { - background-color: #5a32a3; -} - -/* Description - PROMINENT styling */ -.description { - background-color: var(--description-bg); - border-left: 3px solid var(--description-border); - padding: 0.75rem 1rem; - margin: 0.75rem 0; - border-radius: 0 4px 4px 0; -} - -.description p { - margin: 0 0 0.5rem 0; -} - -.description p:last-child { - margin-bottom: 0; -} - -.description code { - background-color: var(--code-bg); - padding: 0.125rem 0.375rem; - border-radius: 3px; - font-family: var(--font-mono); - font-size: 0.875em; - color: var(--code-text); -} - -.description a { - color: var(--accent); -} - -/* Constraints */ -.constraints { - display: flex; - flex-wrap: wrap; - gap: 0.5rem 1rem; - margin: 0.5rem 0; - font-size: 0.875rem; -} - -.constraint { - color: var(--text-secondary); -} - -.constraint .label { - font-weight: 500; -} - -.constraint code { - background-color: var(--code-bg); - padding: 0.125rem 0.375rem; - border-radius: 3px; - font-family: var(--font-mono); - font-size: 0.875em; -} - -/* Default and const values - unified styling */ -.default-value, -.const-value { - margin: 0.5rem 0; - font-size: 0.875rem; - color: var(--text-secondary); -} - -.default-value .label, -.const-value .label { - font-weight: 500; -} - -.default-value code, -.const-value code { - background-color: var(--code-bg); - padding: 0.125rem 0.375rem; - border-radius: 3px; - font-family: var(--font-mono); - font-size: 0.875em; - color: var(--code-text); -} - -/* Nested schemas (details/summary) */ -.nested-schema { - margin: 0.75rem 0; - border: 1px solid var(--border-light); - border-radius: 6px; - overflow: hidden; -} - -.nested-schema > summary { - padding: 0.5rem 1rem; - background-color: var(--bg-tertiary); - cursor: pointer; - font-weight: 500; - font-size: 0.9rem; - user-select: none; - list-style: none; - display: flex; - align-items: center; - gap: 0.5rem; -} - -.nested-schema > summary::-webkit-details-marker { - display: none; -} - -.nested-schema > summary::before { - content: "▶"; - font-size: 0.7rem; - transition: transform 0.15s; -} - -.nested-schema[open] > summary::before { - transform: rotate(90deg); -} - -.nested-schema > summary:hover { - background-color: var(--border-light); -} - -.properties-container, -.array-items, -.tuple-items, -.variants { - padding: 0.5rem 1rem; -} - -/* Depth-based indentation */ -.depth-1 { - margin-left: 0.5rem; -} -.depth-2 { - margin-left: 1rem; -} -.depth-3 { - margin-left: 1.5rem; -} -.depth-4 { - margin-left: 2rem; -} -.depth-5 { - margin-left: 2.5rem; -} - -@media (max-width: 767px) { - .depth-1, - .depth-2, - .depth-3, - .depth-4, - .depth-5 { - margin-left: 0; - } - - /* Prevent horizontal scroll on body */ - body { - overflow-x: hidden; - } - - /* Main content overflow protection */ - .main-content { - overflow-x: hidden; - padding: 1rem; - max-width: 100%; - } - - /* Property name word breaking */ - .property-name { - word-break: break-word; - overflow-wrap: anywhere; - } - - /* Ensure property header wraps properly */ - .property-header { - gap: 0.25rem 0.5rem; - } - - /* Inline code breaking */ - code { - word-break: break-word; - overflow-wrap: anywhere; - } - - /* Pre blocks scroll horizontally inside their container */ - .description pre { - overflow-x: auto; - max-width: 100%; - } - - /* Usage list code paths */ - .usage-list code { - word-break: break-all; - display: inline-block; - max-width: 100%; - } - - /* Enum values - horizontal scroll inside container */ - .enum-values { - overflow-x: auto; - max-width: 100%; - -webkit-overflow-scrolling: touch; - } - - .enum-values code { - word-break: break-word; - max-width: 100%; - } - - /* Type badges and refs - allow wrapping */ - .type-badge, - .type-ref { - margin-top: 0.25rem; - } - - /* Modal for mobile */ - .modal-overlay { - padding: 0.5rem; - } - - .modal { - max-width: 100%; - max-height: 90vh; - } - - .modal-header { - padding: 0.75rem 1rem; - } - - .modal-content { - padding: 1rem; - } - - .modal-title { - font-size: 1rem; - } - - /* Nested schema containers - reduce padding */ - .properties-container, - .array-items, - .tuple-items, - .variants { - padding: 0.5rem; - } - - .nested-schema > summary { - padding: 0.5rem; - } - - /* Search results on mobile */ - .search-result-item { - flex-wrap: wrap; - } - - .result-path { - width: 100%; - word-break: break-word; - overflow-wrap: anywhere; - order: 3; - margin-top: 0.25rem; - } - - .result-type { - order: 2; - } - - /* Description blocks */ - .description { - padding: 0.5rem 0.75rem; - } - - /* Constraints display */ - .constraints { - flex-direction: column; - gap: 0.25rem; - } - - /* Usages section */ - .usages { - padding: 0.5rem 0.75rem; - } - - /* Definition padding */ - .definition { - padding: 1rem; - } - - /* Header title sizing */ - .header h1 { - font-size: 1.25rem; - } - - /* Schema section titles */ - .schema-section > h2 { - font-size: 1.25rem; - } - - /* Definition name sizing */ - .definition-name { - font-size: 1.1rem; - word-break: break-word; - } -} - -/* Variants */ -.variant { - padding: 0.75rem 0; - border-bottom: 1px solid var(--border-light); -} - -.variant:last-child { - border-bottom: none; -} - -/* Tuple items */ -.tuple-item { - padding: 0.5rem 0; - border-bottom: 1px solid var(--border-light); -} - -.tuple-item:last-child { - border-bottom: none; -} - -.tuple-index { - display: inline-block; - font-family: var(--font-mono); - font-size: 0.875rem; - font-weight: 500; - color: var(--text-secondary); - margin-right: 0.5rem; -} - -/* Enum values */ -.enum-values { - list-style: none; - margin: 0; - padding: 0.5rem 1rem; - display: flex; - flex-wrap: wrap; - gap: 0.5rem; -} - -.enum-values li { - margin: 0; -} - -.enum-values code { - display: inline-block; - padding: 0.25rem 0.5rem; - background-color: var(--code-bg); - border-radius: 3px; - font-family: var(--font-mono); - font-size: 0.875rem; -} - -/* Large enum - show as list */ -.enum-details .enum-values { - max-height: 300px; - overflow-y: auto; - flex-direction: column; - gap: 0.25rem; -} - -/* Usages section */ -.usages { - margin: 1rem 0; - padding: 0.75rem 1rem; - background-color: var(--bg-secondary); - border-radius: 6px; - border-left: 3px solid var(--accent); -} - -.usage-section { - margin-bottom: 0.75rem; -} - -.usage-section:last-child { - margin-bottom: 0; -} - -.usage-section h4 { - margin: 0 0 0.25rem 0; - font-size: 0.8rem; - font-weight: 600; - color: var(--text-muted); - text-transform: uppercase; - letter-spacing: 0.03em; -} - -.usage-list { - margin: 0; - padding: 0; - list-style: none; -} - -.usage-list li { - padding: 0.25rem 0; -} - -.usage-list code { - font-size: 0.8125rem; - background-color: var(--code-bg); - padding: 0.125rem 0.375rem; - border-radius: 3px; -} - -.usage-list a { - color: var(--accent); - text-decoration: none; -} - -.usage-list a:hover { - text-decoration: underline; -} - -/* Schema inline (for nested schemas without property wrapper) */ -.schema-inline { - margin: 0.5rem 0; -} - -/* Code blocks in descriptions */ -.description pre { - background-color: var(--code-bg); - padding: 1rem; - border-radius: 6px; - overflow-x: auto; - margin: 0.75rem 0; -} - -.description pre code { - background: none; - padding: 0; - color: var(--text-primary); -} - -/* Scrollbar styling for dark mode */ -@media (prefers-color-scheme: dark) { - ::-webkit-scrollbar { - width: 8px; - height: 8px; - } - - ::-webkit-scrollbar-track { - background: var(--bg-secondary); - } - - ::-webkit-scrollbar-thumb { - background: var(--border); - border-radius: 4px; - } - - ::-webkit-scrollbar-thumb:hover { - background: var(--text-muted); - } -} - -/* Modal overlay */ -.modal-overlay { - display: none; - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: rgba(0, 0, 0, 0.5); - z-index: 1000; - justify-content: center; - align-items: center; - padding: 2rem; -} - -.modal-overlay.modal-active { - display: flex; -} - -.modal { - background: var(--bg-primary); - border-radius: 8px; - max-width: 800px; - max-height: 80vh; - width: 100%; - overflow: hidden; - display: flex; - flex-direction: column; - box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); -} - -.modal-header { - display: flex; - align-items: center; - padding: 1rem 1.5rem; - border-bottom: 1px solid var(--border); - background: var(--bg-secondary); -} - -.modal-nav { - display: flex; - gap: 0.25rem; - margin-right: 0.75rem; -} - -.modal-nav-btn { - background: none; - border: 1px solid var(--border); - border-radius: 4px; - padding: 0.25rem 0.5rem; - cursor: pointer; - color: var(--text-primary); - font-size: 1rem; - line-height: 1; - transition: - background-color 0.15s, - opacity 0.15s; -} - -.modal-nav-btn:hover:not(.disabled) { - background-color: var(--bg-tertiary); -} - -.modal-nav-btn.disabled { - opacity: 0.3; - cursor: not-allowed; -} - -.modal-title { - margin: 0; - font-size: 1.25rem; - color: var(--text-primary); - flex: 1; -} - -.modal-close { - background: none; - border: none; - font-size: 1.5rem; - cursor: pointer; - color: var(--text-secondary); - padding: 0.25rem 0.5rem; - line-height: 1; -} - -.modal-close:hover { - color: var(--text-primary); -} - -.modal-content { - padding: 1.5rem; - overflow-y: auto; - flex: 1; -} - -/* Dark mode modal */ -@media (prefers-color-scheme: dark) { - .modal-overlay { - background: rgba(0, 0, 0, 0.7); - } -} - -/* Print styles */ -@media print { - .header { - position: static; - } - - .sidebar { - display: none; - } - - .layout { - grid-template-columns: 1fr; - } - - .search-container { - display: none; - } - - details { - display: block !important; - } - - details > summary { - display: none; - } - - details > *:not(summary) { - display: block !important; - } -} diff --git a/src/templates/test_index.html b/src/templates/test_index.html deleted file mode 100644 index 64599dca..00000000 --- a/src/templates/test_index.html +++ /dev/null @@ -1,313 +0,0 @@ - - - - - - JSON Schema Test Suite - Generated Documentation - - - -
    -

    JSON Schema Test Suite

    -

    - Generated HTML documentation for draft2020-12 test schemas -

    -
    -
    -
    {{ total_schemas }}
    -
    Total Schemas
    -
    -
    -
    {{ total_files }}
    -
    Test Files
    -
    -
    -
    {{ with_content }}
    -
    With Content
    -
    -
    -
    {{ without_content }}
    -
    Empty (Expected)
    -
    -
    -
    -

    Build Information

    -
    - Commit: - - {{ commit_hash }} {%- if is_dirty %} - dirty - {%- else %} - clean - {%- endif %} - - Time (UTC): - {{ time_utc }} - Time (Local): - {{ time_local }} -
    -
    -
    -

    Legend

    -
    -
    - content - Schema has properties or $defs - - Configuration/Types sections populated -
    -
    - empty - Schema lacks properties/$defs - empty sections - expected -
    -
    -
    - {%- for group in groups %} - - {%- endfor %} -
    - - diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/additionalProperties.json b/tests/fixtures/json-schema-test-suite/draft2020-12/additionalProperties.json deleted file mode 100644 index 9618575e..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/additionalProperties.json +++ /dev/null @@ -1,219 +0,0 @@ -[ - { - "description": - "additionalProperties being false does not allow other properties", - "specification": [ { "core":"10.3.2.3", "quote": "The value of \"additionalProperties\" MUST be a valid JSON Schema. Boolean \"false\" forbids everything." } ], - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": {"foo": {}, "bar": {}}, - "patternProperties": { "^v": {} }, - "additionalProperties": false - }, - "tests": [ - { - "description": "no additional properties is valid", - "data": {"foo": 1}, - "valid": true - }, - { - "description": "an additional property is invalid", - "data": {"foo" : 1, "bar" : 2, "quux" : "boom"}, - "valid": false - }, - { - "description": "ignores arrays", - "data": [1, 2, 3], - "valid": true - }, - { - "description": "ignores strings", - "data": "foobarbaz", - "valid": true - }, - { - "description": "ignores other non-objects", - "data": 12, - "valid": true - }, - { - "description": "patternProperties are not additional properties", - "data": {"foo":1, "vroom": 2}, - "valid": true - } - ] - }, - { - "description": "non-ASCII pattern with additionalProperties", - "specification": [ { "core":"10.3.2.3"} ], - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "patternProperties": {"^á": {}}, - "additionalProperties": false - }, - "tests": [ - { - "description": "matching the pattern is valid", - "data": {"ármányos": 2}, - "valid": true - }, - { - "description": "not matching the pattern is invalid", - "data": {"élmény": 2}, - "valid": false - } - ] - }, - { - "description": "additionalProperties with schema", - "specification": [ { "core":"10.3.2.3", "quote": "The value of \"additionalProperties\" MUST be a valid JSON Schema." } ], - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": {"foo": {}, "bar": {}}, - "additionalProperties": {"type": "boolean"} - }, - "tests": [ - { - "description": "no additional properties is valid", - "data": {"foo": 1}, - "valid": true - }, - { - "description": "an additional valid property is valid", - "data": {"foo" : 1, "bar" : 2, "quux" : true}, - "valid": true - }, - { - "description": "an additional invalid property is invalid", - "data": {"foo" : 1, "bar" : 2, "quux" : 12}, - "valid": false - } - ] - }, - { - "description": "additionalProperties can exist by itself", - "specification": [ { "core":"10.3.2.3", "quote": "With no other applicator applying to object instances. This validates all the instance values irrespective of their property names" } ], - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "additionalProperties": {"type": "boolean"} - }, - "tests": [ - { - "description": "an additional valid property is valid", - "data": {"foo" : true}, - "valid": true - }, - { - "description": "an additional invalid property is invalid", - "data": {"foo" : 1}, - "valid": false - } - ] - }, - { - "description": "additionalProperties are allowed by default", - "specification": [ { "core":"10.3.2.3", "quote": "Omitting this keyword has the same assertion behavior as an empty schema." } ], - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": {"foo": {}, "bar": {}} - }, - "tests": [ - { - "description": "additional properties are allowed", - "data": {"foo": 1, "bar": 2, "quux": true}, - "valid": true - } - ] - }, - { - "description": "additionalProperties does not look in applicators", - "specification":[ { "core": "10.2", "quote": "Subschemas of applicator keywords evaluate the instance completely independently such that the results of one such subschema MUST NOT impact the results of sibling subschemas." } ], - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [ - {"properties": {"foo": {}}} - ], - "additionalProperties": {"type": "boolean"} - }, - "tests": [ - { - "description": "properties defined in allOf are not examined", - "data": {"foo": 1, "bar": true}, - "valid": false - } - ] - }, - { - "description": "additionalProperties with null valued instance properties", - "specification": [ { "core":"10.3.2.3" } ], - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "additionalProperties": { - "type": "null" - } - }, - "tests": [ - { - "description": "allows null values", - "data": {"foo": null}, - "valid": true - } - ] - }, - { - "description": "additionalProperties with propertyNames", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "propertyNames": { - "maxLength": 5 - }, - "additionalProperties": { - "type": "number" - } - }, - "tests": [ - { - "description": "Valid against both keywords", - "data": { "apple": 4 }, - "valid": true - }, - { - "description": "Valid against propertyNames, but not additionalProperties", - "data": { "fig": 2, "pear": "available" }, - "valid": false - } - ] - }, - { - "description": "dependentSchemas with additionalProperties", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": {"foo2": {}}, - "dependentSchemas": { - "foo" : {}, - "foo2": { - "properties": { - "bar": {} - } - } - }, - "additionalProperties": false - }, - "tests": [ - { - "description": "additionalProperties doesn't consider dependentSchemas", - "data": {"foo": ""}, - "valid": false - }, - { - "description": "additionalProperties can't see bar", - "data": {"bar": ""}, - "valid": false - }, - { - "description": "additionalProperties can't see bar even when foo2 is present", - "data": {"foo2": "", "bar": ""}, - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/allOf.json b/tests/fixtures/json-schema-test-suite/draft2020-12/allOf.json deleted file mode 100644 index 9e87903f..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/allOf.json +++ /dev/null @@ -1,312 +0,0 @@ -[ - { - "description": "allOf", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [ - { - "properties": { - "bar": {"type": "integer"} - }, - "required": ["bar"] - }, - { - "properties": { - "foo": {"type": "string"} - }, - "required": ["foo"] - } - ] - }, - "tests": [ - { - "description": "allOf", - "data": {"foo": "baz", "bar": 2}, - "valid": true - }, - { - "description": "mismatch second", - "data": {"foo": "baz"}, - "valid": false - }, - { - "description": "mismatch first", - "data": {"bar": 2}, - "valid": false - }, - { - "description": "wrong type", - "data": {"foo": "baz", "bar": "quux"}, - "valid": false - } - ] - }, - { - "description": "allOf with base schema", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": {"bar": {"type": "integer"}}, - "required": ["bar"], - "allOf" : [ - { - "properties": { - "foo": {"type": "string"} - }, - "required": ["foo"] - }, - { - "properties": { - "baz": {"type": "null"} - }, - "required": ["baz"] - } - ] - }, - "tests": [ - { - "description": "valid", - "data": {"foo": "quux", "bar": 2, "baz": null}, - "valid": true - }, - { - "description": "mismatch base schema", - "data": {"foo": "quux", "baz": null}, - "valid": false - }, - { - "description": "mismatch first allOf", - "data": {"bar": 2, "baz": null}, - "valid": false - }, - { - "description": "mismatch second allOf", - "data": {"foo": "quux", "bar": 2}, - "valid": false - }, - { - "description": "mismatch both", - "data": {"bar": 2}, - "valid": false - } - ] - }, - { - "description": "allOf simple types", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [ - {"maximum": 30}, - {"minimum": 20} - ] - }, - "tests": [ - { - "description": "valid", - "data": 25, - "valid": true - }, - { - "description": "mismatch one", - "data": 35, - "valid": false - } - ] - }, - { - "description": "allOf with boolean schemas, all true", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [true, true] - }, - "tests": [ - { - "description": "any value is valid", - "data": "foo", - "valid": true - } - ] - }, - { - "description": "allOf with boolean schemas, some false", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [true, false] - }, - "tests": [ - { - "description": "any value is invalid", - "data": "foo", - "valid": false - } - ] - }, - { - "description": "allOf with boolean schemas, all false", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [false, false] - }, - "tests": [ - { - "description": "any value is invalid", - "data": "foo", - "valid": false - } - ] - }, - { - "description": "allOf with one empty schema", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [ - {} - ] - }, - "tests": [ - { - "description": "any data is valid", - "data": 1, - "valid": true - } - ] - }, - { - "description": "allOf with two empty schemas", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [ - {}, - {} - ] - }, - "tests": [ - { - "description": "any data is valid", - "data": 1, - "valid": true - } - ] - }, - { - "description": "allOf with the first empty schema", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [ - {}, - { "type": "number" } - ] - }, - "tests": [ - { - "description": "number is valid", - "data": 1, - "valid": true - }, - { - "description": "string is invalid", - "data": "foo", - "valid": false - } - ] - }, - { - "description": "allOf with the last empty schema", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [ - { "type": "number" }, - {} - ] - }, - "tests": [ - { - "description": "number is valid", - "data": 1, - "valid": true - }, - { - "description": "string is invalid", - "data": "foo", - "valid": false - } - ] - }, - { - "description": "nested allOf, to check validation semantics", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [ - { - "allOf": [ - { - "type": "null" - } - ] - } - ] - }, - "tests": [ - { - "description": "null is valid", - "data": null, - "valid": true - }, - { - "description": "anything non-null is invalid", - "data": 123, - "valid": false - } - ] - }, - { - "description": "allOf combined with anyOf, oneOf", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [ { "multipleOf": 2 } ], - "anyOf": [ { "multipleOf": 3 } ], - "oneOf": [ { "multipleOf": 5 } ] - }, - "tests": [ - { - "description": "allOf: false, anyOf: false, oneOf: false", - "data": 1, - "valid": false - }, - { - "description": "allOf: false, anyOf: false, oneOf: true", - "data": 5, - "valid": false - }, - { - "description": "allOf: false, anyOf: true, oneOf: false", - "data": 3, - "valid": false - }, - { - "description": "allOf: false, anyOf: true, oneOf: true", - "data": 15, - "valid": false - }, - { - "description": "allOf: true, anyOf: false, oneOf: false", - "data": 2, - "valid": false - }, - { - "description": "allOf: true, anyOf: false, oneOf: true", - "data": 10, - "valid": false - }, - { - "description": "allOf: true, anyOf: true, oneOf: false", - "data": 6, - "valid": false - }, - { - "description": "allOf: true, anyOf: true, oneOf: true", - "data": 30, - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/anchor.json b/tests/fixtures/json-schema-test-suite/draft2020-12/anchor.json deleted file mode 100644 index 99143fa1..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/anchor.json +++ /dev/null @@ -1,120 +0,0 @@ -[ - { - "description": "Location-independent identifier", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$ref": "#foo", - "$defs": { - "A": { - "$anchor": "foo", - "type": "integer" - } - } - }, - "tests": [ - { - "data": 1, - "description": "match", - "valid": true - }, - { - "data": "a", - "description": "mismatch", - "valid": false - } - ] - }, - { - "description": "Location-independent identifier with absolute URI", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$ref": "http://localhost:1234/draft2020-12/bar#foo", - "$defs": { - "A": { - "$id": "http://localhost:1234/draft2020-12/bar", - "$anchor": "foo", - "type": "integer" - } - } - }, - "tests": [ - { - "data": 1, - "description": "match", - "valid": true - }, - { - "data": "a", - "description": "mismatch", - "valid": false - } - ] - }, - { - "description": "Location-independent identifier with base URI change in subschema", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "http://localhost:1234/draft2020-12/root", - "$ref": "http://localhost:1234/draft2020-12/nested.json#foo", - "$defs": { - "A": { - "$id": "nested.json", - "$defs": { - "B": { - "$anchor": "foo", - "type": "integer" - } - } - } - } - }, - "tests": [ - { - "data": 1, - "description": "match", - "valid": true - }, - { - "data": "a", - "description": "mismatch", - "valid": false - } - ] - }, - { - "description": "same $anchor with different base uri", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "http://localhost:1234/draft2020-12/foobar", - "$defs": { - "A": { - "$id": "child1", - "allOf": [ - { - "$id": "child2", - "$anchor": "my_anchor", - "type": "number" - }, - { - "$anchor": "my_anchor", - "type": "string" - } - ] - } - }, - "$ref": "child1#my_anchor" - }, - "tests": [ - { - "description": "$ref resolves to /$defs/A/allOf/1", - "data": "a", - "valid": true - }, - { - "description": "$ref does not resolve to /$defs/A/allOf/0", - "data": 1, - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/anyOf.json b/tests/fixtures/json-schema-test-suite/draft2020-12/anyOf.json deleted file mode 100644 index 89b192db..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/anyOf.json +++ /dev/null @@ -1,203 +0,0 @@ -[ - { - "description": "anyOf", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "anyOf": [ - { - "type": "integer" - }, - { - "minimum": 2 - } - ] - }, - "tests": [ - { - "description": "first anyOf valid", - "data": 1, - "valid": true - }, - { - "description": "second anyOf valid", - "data": 2.5, - "valid": true - }, - { - "description": "both anyOf valid", - "data": 3, - "valid": true - }, - { - "description": "neither anyOf valid", - "data": 1.5, - "valid": false - } - ] - }, - { - "description": "anyOf with base schema", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "string", - "anyOf" : [ - { - "maxLength": 2 - }, - { - "minLength": 4 - } - ] - }, - "tests": [ - { - "description": "mismatch base schema", - "data": 3, - "valid": false - }, - { - "description": "one anyOf valid", - "data": "foobar", - "valid": true - }, - { - "description": "both anyOf invalid", - "data": "foo", - "valid": false - } - ] - }, - { - "description": "anyOf with boolean schemas, all true", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "anyOf": [true, true] - }, - "tests": [ - { - "description": "any value is valid", - "data": "foo", - "valid": true - } - ] - }, - { - "description": "anyOf with boolean schemas, some true", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "anyOf": [true, false] - }, - "tests": [ - { - "description": "any value is valid", - "data": "foo", - "valid": true - } - ] - }, - { - "description": "anyOf with boolean schemas, all false", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "anyOf": [false, false] - }, - "tests": [ - { - "description": "any value is invalid", - "data": "foo", - "valid": false - } - ] - }, - { - "description": "anyOf complex types", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "anyOf": [ - { - "properties": { - "bar": {"type": "integer"} - }, - "required": ["bar"] - }, - { - "properties": { - "foo": {"type": "string"} - }, - "required": ["foo"] - } - ] - }, - "tests": [ - { - "description": "first anyOf valid (complex)", - "data": {"bar": 2}, - "valid": true - }, - { - "description": "second anyOf valid (complex)", - "data": {"foo": "baz"}, - "valid": true - }, - { - "description": "both anyOf valid (complex)", - "data": {"foo": "baz", "bar": 2}, - "valid": true - }, - { - "description": "neither anyOf valid (complex)", - "data": {"foo": 2, "bar": "quux"}, - "valid": false - } - ] - }, - { - "description": "anyOf with one empty schema", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "anyOf": [ - { "type": "number" }, - {} - ] - }, - "tests": [ - { - "description": "string is valid", - "data": "foo", - "valid": true - }, - { - "description": "number is valid", - "data": 123, - "valid": true - } - ] - }, - { - "description": "nested anyOf, to check validation semantics", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "anyOf": [ - { - "anyOf": [ - { - "type": "null" - } - ] - } - ] - }, - "tests": [ - { - "description": "null is valid", - "data": null, - "valid": true - }, - { - "description": "anything non-null is invalid", - "data": 123, - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/boolean_schema.json b/tests/fixtures/json-schema-test-suite/draft2020-12/boolean_schema.json deleted file mode 100644 index 6d40f23f..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/boolean_schema.json +++ /dev/null @@ -1,104 +0,0 @@ -[ - { - "description": "boolean schema 'true'", - "schema": true, - "tests": [ - { - "description": "number is valid", - "data": 1, - "valid": true - }, - { - "description": "string is valid", - "data": "foo", - "valid": true - }, - { - "description": "boolean true is valid", - "data": true, - "valid": true - }, - { - "description": "boolean false is valid", - "data": false, - "valid": true - }, - { - "description": "null is valid", - "data": null, - "valid": true - }, - { - "description": "object is valid", - "data": {"foo": "bar"}, - "valid": true - }, - { - "description": "empty object is valid", - "data": {}, - "valid": true - }, - { - "description": "array is valid", - "data": ["foo"], - "valid": true - }, - { - "description": "empty array is valid", - "data": [], - "valid": true - } - ] - }, - { - "description": "boolean schema 'false'", - "schema": false, - "tests": [ - { - "description": "number is invalid", - "data": 1, - "valid": false - }, - { - "description": "string is invalid", - "data": "foo", - "valid": false - }, - { - "description": "boolean true is invalid", - "data": true, - "valid": false - }, - { - "description": "boolean false is invalid", - "data": false, - "valid": false - }, - { - "description": "null is invalid", - "data": null, - "valid": false - }, - { - "description": "object is invalid", - "data": {"foo": "bar"}, - "valid": false - }, - { - "description": "empty object is invalid", - "data": {}, - "valid": false - }, - { - "description": "array is invalid", - "data": ["foo"], - "valid": false - }, - { - "description": "empty array is invalid", - "data": [], - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/const.json b/tests/fixtures/json-schema-test-suite/draft2020-12/const.json deleted file mode 100644 index 72ea3f04..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/const.json +++ /dev/null @@ -1,431 +0,0 @@ -[ - { - "description": "const validation", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "const": 2 - }, - "tests": [ - { - "description": "same value is valid", - "data": 2, - "valid": true - }, - { - "description": "another value is invalid", - "data": 5, - "valid": false - }, - { - "description": "another type is invalid", - "data": "a", - "valid": false - } - ] - }, - { - "description": "const with object", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "const": {"foo": "bar", "baz": "bax"} - }, - "tests": [ - { - "description": "same object is valid", - "data": {"foo": "bar", "baz": "bax"}, - "valid": true - }, - { - "description": "same object with different property order is valid", - "data": {"baz": "bax", "foo": "bar"}, - "valid": true - }, - { - "description": "another object is invalid", - "data": {"foo": "bar"}, - "valid": false - }, - { - "description": "another type is invalid", - "data": [1, 2], - "valid": false - } - ] - }, - { - "description": "const with array", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "const": [{ "foo": "bar" }] - }, - "tests": [ - { - "description": "same array is valid", - "data": [{"foo": "bar"}], - "valid": true - }, - { - "description": "another array item is invalid", - "data": [2], - "valid": false - }, - { - "description": "array with additional items is invalid", - "data": [1, 2, 3], - "valid": false - } - ] - }, - { - "description": "const with null", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "const": null - }, - "tests": [ - { - "description": "null is valid", - "data": null, - "valid": true - }, - { - "description": "not null is invalid", - "data": 0, - "valid": false - } - ] - }, - { - "description": "const with false does not match 0", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "const": false - }, - "tests": [ - { - "description": "false is valid", - "data": false, - "valid": true - }, - { - "description": "integer zero is invalid", - "data": 0, - "valid": false - }, - { - "description": "float zero is invalid", - "data": 0.0, - "valid": false - } - ] - }, - { - "description": "const with true does not match 1", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "const": true - }, - "tests": [ - { - "description": "true is valid", - "data": true, - "valid": true - }, - { - "description": "integer one is invalid", - "data": 1, - "valid": false - }, - { - "description": "float one is invalid", - "data": 1.0, - "valid": false - } - ] - }, - { - "description": "const with [false] does not match [0]", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "const": [false] - }, - "tests": [ - { - "description": "[false] is valid", - "data": [false], - "valid": true - }, - { - "description": "[0] is invalid", - "data": [0], - "valid": false - }, - { - "description": "[0.0] is invalid", - "data": [0.0], - "valid": false - } - ] - }, - { - "description": "const with [true] does not match [1]", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "const": [true] - }, - "tests": [ - { - "description": "[true] is valid", - "data": [true], - "valid": true - }, - { - "description": "[1] is invalid", - "data": [1], - "valid": false - }, - { - "description": "[1.0] is invalid", - "data": [1.0], - "valid": false - } - ] - }, - { - "description": "const with {\"a\": false} does not match {\"a\": 0}", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "const": {"a": false} - }, - "tests": [ - { - "description": "{\"a\": false} is valid", - "data": {"a": false}, - "valid": true - }, - { - "description": "{\"a\": 0} is invalid", - "data": {"a": 0}, - "valid": false - }, - { - "description": "{\"a\": 0.0} is invalid", - "data": {"a": 0.0}, - "valid": false - } - ] - }, - { - "description": "const with {\"a\": true} does not match {\"a\": 1}", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "const": {"a": true} - }, - "tests": [ - { - "description": "{\"a\": true} is valid", - "data": {"a": true}, - "valid": true - }, - { - "description": "{\"a\": 1} is invalid", - "data": {"a": 1}, - "valid": false - }, - { - "description": "{\"a\": 1.0} is invalid", - "data": {"a": 1.0}, - "valid": false - } - ] - }, - { - "description": "const with 0 does not match other zero-like types", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "const": 0 - }, - "tests": [ - { - "description": "false is invalid", - "data": false, - "valid": false - }, - { - "description": "integer zero is valid", - "data": 0, - "valid": true - }, - { - "description": "float zero is valid", - "data": 0.0, - "valid": true - }, - { - "description": "empty object is invalid", - "data": {}, - "valid": false - }, - { - "description": "empty array is invalid", - "data": [], - "valid": false - }, - { - "description": "empty string is invalid", - "data": "", - "valid": false - } - ] - }, - { - "description": "const with 1 does not match true", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "const": 1 - }, - "tests": [ - { - "description": "true is invalid", - "data": true, - "valid": false - }, - { - "description": "integer one is valid", - "data": 1, - "valid": true - }, - { - "description": "float one is valid", - "data": 1.0, - "valid": true - } - ] - }, - { - "description": "const with -2.0 matches integer and float types", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "const": -2.0 - }, - "tests": [ - { - "description": "integer -2 is valid", - "data": -2, - "valid": true - }, - { - "description": "integer 2 is invalid", - "data": 2, - "valid": false - }, - { - "description": "float -2.0 is valid", - "data": -2.0, - "valid": true - }, - { - "description": "float 2.0 is invalid", - "data": 2.0, - "valid": false - }, - { - "description": "float -2.00001 is invalid", - "data": -2.00001, - "valid": false - } - ] - }, - { - "description": "float and integers are equal up to 64-bit representation limits", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "const": 9007199254740992 - }, - "tests": [ - { - "description": "integer is valid", - "data": 9007199254740992, - "valid": true - }, - { - "description": "integer minus one is invalid", - "data": 9007199254740991, - "valid": false - }, - { - "description": "float is valid", - "data": 9007199254740992.0, - "valid": true - }, - { - "description": "float minus one is invalid", - "data": 9007199254740991.0, - "valid": false - } - ] - }, - { - "description": "nul characters in strings", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "const": "hello\u0000there" - }, - "tests": [ - { - "description": "match string with nul", - "data": "hello\u0000there", - "valid": true - }, - { - "description": "do not match string lacking nul", - "data": "hellothere", - "valid": false - } - ] - }, - { - "description": "characters with the same visual representation but different codepoint", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "const": "μ", - "$comment": "U+03BC" - }, - "tests": [ - { - "description": "character uses the same codepoint", - "data": "μ", - "comment": "U+03BC", - "valid": true - }, - { - "description": "character looks the same but uses a different codepoint", - "data": "µ", - "comment": "U+00B5", - "valid": false - } - ] - }, - { - "description": "characters with the same visual representation, but different number of codepoints", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "const": "ä", - "$comment": "U+00E4" - }, - "tests": [ - { - "description": "character uses the same codepoint", - "data": "ä", - "comment": "U+00E4", - "valid": true - }, - { - "description": "character looks the same but uses combining marks", - "data": "ä", - "comment": "a, U+0308", - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/contains.json b/tests/fixtures/json-schema-test-suite/draft2020-12/contains.json deleted file mode 100644 index 08a00a75..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/contains.json +++ /dev/null @@ -1,176 +0,0 @@ -[ - { - "description": "contains keyword validation", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "contains": {"minimum": 5} - }, - "tests": [ - { - "description": "array with item matching schema (5) is valid", - "data": [3, 4, 5], - "valid": true - }, - { - "description": "array with item matching schema (6) is valid", - "data": [3, 4, 6], - "valid": true - }, - { - "description": "array with two items matching schema (5, 6) is valid", - "data": [3, 4, 5, 6], - "valid": true - }, - { - "description": "array without items matching schema is invalid", - "data": [2, 3, 4], - "valid": false - }, - { - "description": "empty array is invalid", - "data": [], - "valid": false - }, - { - "description": "not array is valid", - "data": {}, - "valid": true - } - ] - }, - { - "description": "contains keyword with const keyword", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "contains": { "const": 5 } - }, - "tests": [ - { - "description": "array with item 5 is valid", - "data": [3, 4, 5], - "valid": true - }, - { - "description": "array with two items 5 is valid", - "data": [3, 4, 5, 5], - "valid": true - }, - { - "description": "array without item 5 is invalid", - "data": [1, 2, 3, 4], - "valid": false - } - ] - }, - { - "description": "contains keyword with boolean schema true", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "contains": true - }, - "tests": [ - { - "description": "any non-empty array is valid", - "data": ["foo"], - "valid": true - }, - { - "description": "empty array is invalid", - "data": [], - "valid": false - } - ] - }, - { - "description": "contains keyword with boolean schema false", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "contains": false - }, - "tests": [ - { - "description": "any non-empty array is invalid", - "data": ["foo"], - "valid": false - }, - { - "description": "empty array is invalid", - "data": [], - "valid": false - }, - { - "description": "non-arrays are valid", - "data": "contains does not apply to strings", - "valid": true - } - ] - }, - { - "description": "items + contains", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "items": { "multipleOf": 2 }, - "contains": { "multipleOf": 3 } - }, - "tests": [ - { - "description": "matches items, does not match contains", - "data": [ 2, 4, 8 ], - "valid": false - }, - { - "description": "does not match items, matches contains", - "data": [ 3, 6, 9 ], - "valid": false - }, - { - "description": "matches both items and contains", - "data": [ 6, 12 ], - "valid": true - }, - { - "description": "matches neither items nor contains", - "data": [ 1, 5 ], - "valid": false - } - ] - }, - { - "description": "contains with false if subschema", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "contains": { - "if": false, - "else": true - } - }, - "tests": [ - { - "description": "any non-empty array is valid", - "data": ["foo"], - "valid": true - }, - { - "description": "empty array is invalid", - "data": [], - "valid": false - } - ] - }, - { - "description": "contains with null instance elements", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "contains": { - "type": "null" - } - }, - "tests": [ - { - "description": "allows null items", - "data": [ null ], - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/content.json b/tests/fixtures/json-schema-test-suite/draft2020-12/content.json deleted file mode 100644 index 698f7805..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/content.json +++ /dev/null @@ -1,131 +0,0 @@ -[ - { - "description": "validation of string-encoded content based on media type", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "contentMediaType": "application/json" - }, - "tests": [ - { - "description": "a valid JSON document", - "data": "{\"foo\": \"bar\"}", - "valid": true - }, - { - "description": "an invalid JSON document; validates true", - "data": "{:}", - "valid": true - }, - { - "description": "ignores non-strings", - "data": 100, - "valid": true - } - ] - }, - { - "description": "validation of binary string-encoding", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "contentEncoding": "base64" - }, - "tests": [ - { - "description": "a valid base64 string", - "data": "eyJmb28iOiAiYmFyIn0K", - "valid": true - }, - { - "description": "an invalid base64 string (% is not a valid character); validates true", - "data": "eyJmb28iOi%iYmFyIn0K", - "valid": true - }, - { - "description": "ignores non-strings", - "data": 100, - "valid": true - } - ] - }, - { - "description": "validation of binary-encoded media type documents", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "contentMediaType": "application/json", - "contentEncoding": "base64" - }, - "tests": [ - { - "description": "a valid base64-encoded JSON document", - "data": "eyJmb28iOiAiYmFyIn0K", - "valid": true - }, - { - "description": "a validly-encoded invalid JSON document; validates true", - "data": "ezp9Cg==", - "valid": true - }, - { - "description": "an invalid base64 string that is valid JSON; validates true", - "data": "{}", - "valid": true - }, - { - "description": "ignores non-strings", - "data": 100, - "valid": true - } - ] - }, - { - "description": "validation of binary-encoded media type documents with schema", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "contentMediaType": "application/json", - "contentEncoding": "base64", - "contentSchema": { "type": "object", "required": ["foo"], "properties": { "foo": { "type": "string" } } } - }, - "tests": [ - { - "description": "a valid base64-encoded JSON document", - "data": "eyJmb28iOiAiYmFyIn0K", - "valid": true - }, - { - "description": "another valid base64-encoded JSON document", - "data": "eyJib28iOiAyMCwgImZvbyI6ICJiYXoifQ==", - "valid": true - }, - { - "description": "an invalid base64-encoded JSON document; validates true", - "data": "eyJib28iOiAyMH0=", - "valid": true - }, - { - "description": "an empty object as a base64-encoded JSON document; validates true", - "data": "e30=", - "valid": true - }, - { - "description": "an empty array as a base64-encoded JSON document", - "data": "W10=", - "valid": true - }, - { - "description": "a validly-encoded invalid JSON document; validates true", - "data": "ezp9Cg==", - "valid": true - }, - { - "description": "an invalid base64 string that is valid JSON; validates true", - "data": "{}", - "valid": true - }, - { - "description": "ignores non-strings", - "data": 100, - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/default.json b/tests/fixtures/json-schema-test-suite/draft2020-12/default.json deleted file mode 100644 index ceb3ae27..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/default.json +++ /dev/null @@ -1,82 +0,0 @@ -[ - { - "description": "invalid type for default", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": { - "type": "integer", - "default": [] - } - } - }, - "tests": [ - { - "description": "valid when property is specified", - "data": {"foo": 13}, - "valid": true - }, - { - "description": "still valid when the invalid default is used", - "data": {}, - "valid": true - } - ] - }, - { - "description": "invalid string value for default", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "bar": { - "type": "string", - "minLength": 4, - "default": "bad" - } - } - }, - "tests": [ - { - "description": "valid when property is specified", - "data": {"bar": "good"}, - "valid": true - }, - { - "description": "still valid when the invalid default is used", - "data": {}, - "valid": true - } - ] - }, - { - "description": "the default keyword does not do anything if the property is missing", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "properties": { - "alpha": { - "type": "number", - "maximum": 3, - "default": 5 - } - } - }, - "tests": [ - { - "description": "an explicit property value is checked against maximum (passing)", - "data": { "alpha": 1 }, - "valid": true - }, - { - "description": "an explicit property value is checked against maximum (failing)", - "data": { "alpha": 5 }, - "valid": false - }, - { - "description": "missing properties are not filled in with the default", - "data": {}, - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/defs.json b/tests/fixtures/json-schema-test-suite/draft2020-12/defs.json deleted file mode 100644 index da2a503b..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/defs.json +++ /dev/null @@ -1,21 +0,0 @@ -[ - { - "description": "validate definition against metaschema", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$ref": "https://json-schema.org/draft/2020-12/schema" - }, - "tests": [ - { - "description": "valid definition schema", - "data": {"$defs": {"foo": {"type": "integer"}}}, - "valid": true - }, - { - "description": "invalid definition schema", - "data": {"$defs": {"foo": {"type": 1}}}, - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/dependentRequired.json b/tests/fixtures/json-schema-test-suite/draft2020-12/dependentRequired.json deleted file mode 100644 index 2baa38e9..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/dependentRequired.json +++ /dev/null @@ -1,152 +0,0 @@ -[ - { - "description": "single dependency", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "dependentRequired": {"bar": ["foo"]} - }, - "tests": [ - { - "description": "neither", - "data": {}, - "valid": true - }, - { - "description": "nondependant", - "data": {"foo": 1}, - "valid": true - }, - { - "description": "with dependency", - "data": {"foo": 1, "bar": 2}, - "valid": true - }, - { - "description": "missing dependency", - "data": {"bar": 2}, - "valid": false - }, - { - "description": "ignores arrays", - "data": ["bar"], - "valid": true - }, - { - "description": "ignores strings", - "data": "foobar", - "valid": true - }, - { - "description": "ignores other non-objects", - "data": 12, - "valid": true - } - ] - }, - { - "description": "empty dependents", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "dependentRequired": {"bar": []} - }, - "tests": [ - { - "description": "empty object", - "data": {}, - "valid": true - }, - { - "description": "object with one property", - "data": {"bar": 2}, - "valid": true - }, - { - "description": "non-object is valid", - "data": 1, - "valid": true - } - ] - }, - { - "description": "multiple dependents required", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "dependentRequired": {"quux": ["foo", "bar"]} - }, - "tests": [ - { - "description": "neither", - "data": {}, - "valid": true - }, - { - "description": "nondependants", - "data": {"foo": 1, "bar": 2}, - "valid": true - }, - { - "description": "with dependencies", - "data": {"foo": 1, "bar": 2, "quux": 3}, - "valid": true - }, - { - "description": "missing dependency", - "data": {"foo": 1, "quux": 2}, - "valid": false - }, - { - "description": "missing other dependency", - "data": {"bar": 1, "quux": 2}, - "valid": false - }, - { - "description": "missing both dependencies", - "data": {"quux": 1}, - "valid": false - } - ] - }, - { - "description": "dependencies with escaped characters", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "dependentRequired": { - "foo\nbar": ["foo\rbar"], - "foo\"bar": ["foo'bar"] - } - }, - "tests": [ - { - "description": "CRLF", - "data": { - "foo\nbar": 1, - "foo\rbar": 2 - }, - "valid": true - }, - { - "description": "quoted quotes", - "data": { - "foo'bar": 1, - "foo\"bar": 2 - }, - "valid": true - }, - { - "description": "CRLF missing dependent", - "data": { - "foo\nbar": 1, - "foo": 2 - }, - "valid": false - }, - { - "description": "quoted quotes missing dependent", - "data": { - "foo\"bar": 2 - }, - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/dependentSchemas.json b/tests/fixtures/json-schema-test-suite/draft2020-12/dependentSchemas.json deleted file mode 100644 index 1c5f0574..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/dependentSchemas.json +++ /dev/null @@ -1,171 +0,0 @@ -[ - { - "description": "single dependency", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "dependentSchemas": { - "bar": { - "properties": { - "foo": {"type": "integer"}, - "bar": {"type": "integer"} - } - } - } - }, - "tests": [ - { - "description": "valid", - "data": {"foo": 1, "bar": 2}, - "valid": true - }, - { - "description": "no dependency", - "data": {"foo": "quux"}, - "valid": true - }, - { - "description": "wrong type", - "data": {"foo": "quux", "bar": 2}, - "valid": false - }, - { - "description": "wrong type other", - "data": {"foo": 2, "bar": "quux"}, - "valid": false - }, - { - "description": "wrong type both", - "data": {"foo": "quux", "bar": "quux"}, - "valid": false - }, - { - "description": "ignores arrays", - "data": ["bar"], - "valid": true - }, - { - "description": "ignores strings", - "data": "foobar", - "valid": true - }, - { - "description": "ignores other non-objects", - "data": 12, - "valid": true - } - ] - }, - { - "description": "boolean subschemas", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "dependentSchemas": { - "foo": true, - "bar": false - } - }, - "tests": [ - { - "description": "object with property having schema true is valid", - "data": {"foo": 1}, - "valid": true - }, - { - "description": "object with property having schema false is invalid", - "data": {"bar": 2}, - "valid": false - }, - { - "description": "object with both properties is invalid", - "data": {"foo": 1, "bar": 2}, - "valid": false - }, - { - "description": "empty object is valid", - "data": {}, - "valid": true - } - ] - }, - { - "description": "dependencies with escaped characters", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "dependentSchemas": { - "foo\tbar": {"minProperties": 4}, - "foo'bar": {"required": ["foo\"bar"]} - } - }, - "tests": [ - { - "description": "quoted tab", - "data": { - "foo\tbar": 1, - "a": 2, - "b": 3, - "c": 4 - }, - "valid": true - }, - { - "description": "quoted quote", - "data": { - "foo'bar": {"foo\"bar": 1} - }, - "valid": false - }, - { - "description": "quoted tab invalid under dependent schema", - "data": { - "foo\tbar": 1, - "a": 2 - }, - "valid": false - }, - { - "description": "quoted quote invalid under dependent schema", - "data": {"foo'bar": 1}, - "valid": false - } - ] - }, - { - "description": "dependent subschema incompatible with root", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": {} - }, - "dependentSchemas": { - "foo": { - "properties": { - "bar": {} - }, - "additionalProperties": false - } - } - }, - "tests": [ - { - "description": "matches root", - "data": {"foo": 1}, - "valid": false - }, - { - "description": "matches dependency", - "data": {"bar": 1}, - "valid": true - }, - { - "description": "matches both", - "data": {"foo": 1, "bar": 2}, - "valid": false - }, - { - "description": "no dependency", - "data": {"baz": 1}, - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/dynamicRef.json b/tests/fixtures/json-schema-test-suite/draft2020-12/dynamicRef.json deleted file mode 100644 index 50555e84..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/dynamicRef.json +++ /dev/null @@ -1,873 +0,0 @@ -[ - { - "description": "A $dynamicRef to a $dynamicAnchor in the same schema resource behaves like a normal $ref to an $anchor", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://test.json-schema.org/dynamicRef-dynamicAnchor-same-schema/root", - "type": "array", - "items": { "$dynamicRef": "#items" }, - "$defs": { - "foo": { - "$dynamicAnchor": "items", - "type": "string" - } - } - }, - "tests": [ - { - "description": "An array of strings is valid", - "data": ["foo", "bar"], - "valid": true - }, - { - "description": "An array containing non-strings is invalid", - "data": ["foo", 42], - "valid": false - } - ] - }, - { - "description": "A $dynamicRef to an $anchor in the same schema resource behaves like a normal $ref to an $anchor", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://test.json-schema.org/dynamicRef-anchor-same-schema/root", - "type": "array", - "items": { "$dynamicRef": "#items" }, - "$defs": { - "foo": { - "$anchor": "items", - "type": "string" - } - } - }, - "tests": [ - { - "description": "An array of strings is valid", - "data": ["foo", "bar"], - "valid": true - }, - { - "description": "An array containing non-strings is invalid", - "data": ["foo", 42], - "valid": false - } - ] - }, - { - "description": "A $ref to a $dynamicAnchor in the same schema resource behaves like a normal $ref to an $anchor", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://test.json-schema.org/ref-dynamicAnchor-same-schema/root", - "type": "array", - "items": { "$ref": "#items" }, - "$defs": { - "foo": { - "$dynamicAnchor": "items", - "type": "string" - } - } - }, - "tests": [ - { - "description": "An array of strings is valid", - "data": ["foo", "bar"], - "valid": true - }, - { - "description": "An array containing non-strings is invalid", - "data": ["foo", 42], - "valid": false - } - ] - }, - { - "description": "A $dynamicRef resolves to the first $dynamicAnchor still in scope that is encountered when the schema is evaluated", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://test.json-schema.org/typical-dynamic-resolution/root", - "$ref": "list", - "$defs": { - "foo": { - "$dynamicAnchor": "items", - "type": "string" - }, - "list": { - "$id": "list", - "type": "array", - "items": { "$dynamicRef": "#items" }, - "$defs": { - "items": { - "$comment": "This is only needed to satisfy the bookending requirement", - "$dynamicAnchor": "items" - } - } - } - } - }, - "tests": [ - { - "description": "An array of strings is valid", - "data": ["foo", "bar"], - "valid": true - }, - { - "description": "An array containing non-strings is invalid", - "data": ["foo", 42], - "valid": false - } - ] - }, - { - "description": "A $dynamicRef without anchor in fragment behaves identical to $ref", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://test.json-schema.org/dynamicRef-without-anchor/root", - "$ref": "list", - "$defs": { - "foo": { - "$dynamicAnchor": "items", - "type": "string" - }, - "list": { - "$id": "list", - "type": "array", - "items": { "$dynamicRef": "#/$defs/items" }, - "$defs": { - "items": { - "$comment": "This is only needed to satisfy the bookending requirement", - "$dynamicAnchor": "items", - "type": "number" - } - } - } - } - }, - "tests": [ - { - "description": "An array of strings is invalid", - "data": ["foo", "bar"], - "valid": false - }, - { - "description": "An array of numbers is valid", - "data": [24, 42], - "valid": true - } - ] - }, - { - "description": "A $dynamicRef with intermediate scopes that don't include a matching $dynamicAnchor does not affect dynamic scope resolution", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://test.json-schema.org/dynamic-resolution-with-intermediate-scopes/root", - "$ref": "intermediate-scope", - "$defs": { - "foo": { - "$dynamicAnchor": "items", - "type": "string" - }, - "intermediate-scope": { - "$id": "intermediate-scope", - "$ref": "list" - }, - "list": { - "$id": "list", - "type": "array", - "items": { "$dynamicRef": "#items" }, - "$defs": { - "items": { - "$comment": "This is only needed to satisfy the bookending requirement", - "$dynamicAnchor": "items" - } - } - } - } - }, - "tests": [ - { - "description": "An array of strings is valid", - "data": ["foo", "bar"], - "valid": true - }, - { - "description": "An array containing non-strings is invalid", - "data": ["foo", 42], - "valid": false - } - ] - }, - { - "description": "An $anchor with the same name as a $dynamicAnchor is not used for dynamic scope resolution", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://test.json-schema.org/dynamic-resolution-ignores-anchors/root", - "$ref": "list", - "$defs": { - "foo": { - "$anchor": "items", - "type": "string" - }, - "list": { - "$id": "list", - "type": "array", - "items": { "$dynamicRef": "#items" }, - "$defs": { - "items": { - "$comment": "This is only needed to satisfy the bookending requirement", - "$dynamicAnchor": "items" - } - } - } - } - }, - "tests": [ - { - "description": "Any array is valid", - "data": ["foo", 42], - "valid": true - } - ] - }, - { - "description": "A $dynamicRef without a matching $dynamicAnchor in the same schema resource behaves like a normal $ref to $anchor", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://test.json-schema.org/dynamic-resolution-without-bookend/root", - "$ref": "list", - "$defs": { - "foo": { - "$dynamicAnchor": "items", - "type": "string" - }, - "list": { - "$id": "list", - "type": "array", - "items": { "$dynamicRef": "#items" }, - "$defs": { - "items": { - "$comment": "This is only needed to give the reference somewhere to resolve to when it behaves like $ref", - "$anchor": "items" - } - } - } - } - }, - "tests": [ - { - "description": "Any array is valid", - "data": ["foo", 42], - "valid": true - } - ] - }, - { - "description": "A $dynamicRef with a non-matching $dynamicAnchor in the same schema resource behaves like a normal $ref to $anchor", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://test.json-schema.org/unmatched-dynamic-anchor/root", - "$ref": "list", - "$defs": { - "foo": { - "$dynamicAnchor": "items", - "type": "string" - }, - "list": { - "$id": "list", - "type": "array", - "items": { "$dynamicRef": "#items" }, - "$defs": { - "items": { - "$comment": "This is only needed to give the reference somewhere to resolve to when it behaves like $ref", - "$anchor": "items", - "$dynamicAnchor": "foo" - } - } - } - } - }, - "tests": [ - { - "description": "Any array is valid", - "data": ["foo", 42], - "valid": true - } - ] - }, - { - "description": "A $dynamicRef that initially resolves to a schema with a matching $dynamicAnchor resolves to the first $dynamicAnchor in the dynamic scope", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://test.json-schema.org/relative-dynamic-reference/root", - "$dynamicAnchor": "meta", - "type": "object", - "properties": { - "foo": { "const": "pass" } - }, - "$ref": "extended", - "$defs": { - "extended": { - "$id": "extended", - "$dynamicAnchor": "meta", - "type": "object", - "properties": { - "bar": { "$ref": "bar" } - } - }, - "bar": { - "$id": "bar", - "type": "object", - "properties": { - "baz": { "$dynamicRef": "extended#meta" } - } - } - } - }, - "tests": [ - { - "description": "The recursive part is valid against the root", - "data": { - "foo": "pass", - "bar": { - "baz": { "foo": "pass" } - } - }, - "valid": true - }, - { - "description": "The recursive part is not valid against the root", - "data": { - "foo": "pass", - "bar": { - "baz": { "foo": "fail" } - } - }, - "valid": false - } - ] - }, - { - "description": "A $dynamicRef that initially resolves to a schema without a matching $dynamicAnchor behaves like a normal $ref to $anchor", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://test.json-schema.org/relative-dynamic-reference-without-bookend/root", - "$dynamicAnchor": "meta", - "type": "object", - "properties": { - "foo": { "const": "pass" } - }, - "$ref": "extended", - "$defs": { - "extended": { - "$id": "extended", - "$anchor": "meta", - "type": "object", - "properties": { - "bar": { "$ref": "bar" } - } - }, - "bar": { - "$id": "bar", - "type": "object", - "properties": { - "baz": { "$dynamicRef": "extended#meta" } - } - } - } - }, - "tests": [ - { - "description": "The recursive part doesn't need to validate against the root", - "data": { - "foo": "pass", - "bar": { - "baz": { "foo": "fail" } - } - }, - "valid": true - } - ] - }, - { - "description": "multiple dynamic paths to the $dynamicRef keyword", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://test.json-schema.org/dynamic-ref-with-multiple-paths/main", - "if": { - "properties": { - "kindOfList": { "const": "numbers" } - }, - "required": ["kindOfList"] - }, - "then": { "$ref": "numberList" }, - "else": { "$ref": "stringList" }, - - "$defs": { - "genericList": { - "$id": "genericList", - "properties": { - "list": { - "items": { "$dynamicRef": "#itemType" } - } - }, - "$defs": { - "defaultItemType": { - "$comment": "Only needed to satisfy bookending requirement", - "$dynamicAnchor": "itemType" - } - } - }, - "numberList": { - "$id": "numberList", - "$defs": { - "itemType": { - "$dynamicAnchor": "itemType", - "type": "number" - } - }, - "$ref": "genericList" - }, - "stringList": { - "$id": "stringList", - "$defs": { - "itemType": { - "$dynamicAnchor": "itemType", - "type": "string" - } - }, - "$ref": "genericList" - } - } - }, - "tests": [ - { - "description": "number list with number values", - "data": { - "kindOfList": "numbers", - "list": [1.1] - }, - "valid": true - }, - { - "description": "number list with string values", - "data": { - "kindOfList": "numbers", - "list": ["foo"] - }, - "valid": false - }, - { - "description": "string list with number values", - "data": { - "kindOfList": "strings", - "list": [1.1] - }, - "valid": false - }, - { - "description": "string list with string values", - "data": { - "kindOfList": "strings", - "list": ["foo"] - }, - "valid": true - } - ] - }, - { - "description": "after leaving a dynamic scope, it is not used by a $dynamicRef", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://test.json-schema.org/dynamic-ref-leaving-dynamic-scope/main", - "if": { - "$id": "first_scope", - "$defs": { - "thingy": { - "$comment": "this is first_scope#thingy", - "$dynamicAnchor": "thingy", - "type": "number" - } - } - }, - "then": { - "$id": "second_scope", - "$ref": "start", - "$defs": { - "thingy": { - "$comment": "this is second_scope#thingy, the final destination of the $dynamicRef", - "$dynamicAnchor": "thingy", - "type": "null" - } - } - }, - "$defs": { - "start": { - "$comment": "this is the landing spot from $ref", - "$id": "start", - "$dynamicRef": "inner_scope#thingy" - }, - "thingy": { - "$comment": "this is the first stop for the $dynamicRef", - "$id": "inner_scope", - "$dynamicAnchor": "thingy", - "type": "string" - } - } - }, - "tests": [ - { - "description": "string matches /$defs/thingy, but the $dynamicRef does not stop here", - "data": "a string", - "valid": false - }, - { - "description": "first_scope is not in dynamic scope for the $dynamicRef", - "data": 42, - "valid": false - }, - { - "description": "/then/$defs/thingy is the final stop for the $dynamicRef", - "data": null, - "valid": true - } - ] - }, - { - "description": "strict-tree schema, guards against misspelled properties", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "http://localhost:1234/draft2020-12/strict-tree.json", - "$dynamicAnchor": "node", - - "$ref": "tree.json", - "unevaluatedProperties": false - }, - "tests": [ - { - "description": "instance with misspelled field", - "data": { - "children": [{ - "daat": 1 - }] - }, - "valid": false - }, - { - "description": "instance with correct field", - "data": { - "children": [{ - "data": 1 - }] - }, - "valid": true - } - ] - }, - { - "description": "tests for implementation dynamic anchor and reference link", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "http://localhost:1234/draft2020-12/strict-extendible.json", - "$ref": "extendible-dynamic-ref.json", - "$defs": { - "elements": { - "$dynamicAnchor": "elements", - "properties": { - "a": true - }, - "required": ["a"], - "additionalProperties": false - } - } - }, - "tests": [ - { - "description": "incorrect parent schema", - "data": { - "a": true - }, - "valid": false - }, - { - "description": "incorrect extended schema", - "data": { - "elements": [ - { "b": 1 } - ] - }, - "valid": false - }, - { - "description": "correct extended schema", - "data": { - "elements": [ - { "a": 1 } - ] - }, - "valid": true - } - ] - }, - { - "description": "$ref and $dynamicAnchor are independent of order - $defs first", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "http://localhost:1234/draft2020-12/strict-extendible-allof-defs-first.json", - "allOf": [ - { - "$ref": "extendible-dynamic-ref.json" - }, - { - "$defs": { - "elements": { - "$dynamicAnchor": "elements", - "properties": { - "a": true - }, - "required": ["a"], - "additionalProperties": false - } - } - } - ] - }, - "tests": [ - { - "description": "incorrect parent schema", - "data": { - "a": true - }, - "valid": false - }, - { - "description": "incorrect extended schema", - "data": { - "elements": [ - { "b": 1 } - ] - }, - "valid": false - }, - { - "description": "correct extended schema", - "data": { - "elements": [ - { "a": 1 } - ] - }, - "valid": true - } - ] - }, - { - "description": "$ref and $dynamicAnchor are independent of order - $ref first", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "http://localhost:1234/draft2020-12/strict-extendible-allof-ref-first.json", - "allOf": [ - { - "$defs": { - "elements": { - "$dynamicAnchor": "elements", - "properties": { - "a": true - }, - "required": ["a"], - "additionalProperties": false - } - } - }, - { - "$ref": "extendible-dynamic-ref.json" - } - ] - }, - "tests": [ - { - "description": "incorrect parent schema", - "data": { - "a": true - }, - "valid": false - }, - { - "description": "incorrect extended schema", - "data": { - "elements": [ - { "b": 1 } - ] - }, - "valid": false - }, - { - "description": "correct extended schema", - "data": { - "elements": [ - { "a": 1 } - ] - }, - "valid": true - } - ] - }, - { - "description": "$ref to $dynamicRef finds detached $dynamicAnchor", - "schema": { - "$ref": "http://localhost:1234/draft2020-12/detached-dynamicref.json#/$defs/foo" - }, - "tests": [ - { - "description": "number is valid", - "data": 1, - "valid": true - }, - { - "description": "non-number is invalid", - "data": "a", - "valid": false - } - ] - }, - { - "description": "$dynamicRef points to a boolean schema", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$defs": { - "true": true, - "false": false - }, - "properties": { - "true": { - "$dynamicRef": "#/$defs/true" - }, - "false": { - "$dynamicRef": "#/$defs/false" - } - } - }, - "tests": [ - { - "description": "follow $dynamicRef to a true schema", - "data": { "true": 1 }, - "valid": true - }, - { - "description": "follow $dynamicRef to a false schema", - "data": { "false": 1 }, - "valid": false - } - ] - }, - { - "description": "$dynamicRef skips over intermediate resources - direct reference", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://test.json-schema.org/dynamic-ref-skips-intermediate-resource/main", - "type": "object", - "properties": { - "bar-item": { - "$ref": "item" - } - }, - "$defs": { - "bar": { - "$id": "bar", - "type": "array", - "items": { - "$ref": "item" - }, - "$defs": { - "item": { - "$id": "item", - "type": "object", - "properties": { - "content": { - "$dynamicRef": "#content" - } - }, - "$defs": { - "defaultContent": { - "$dynamicAnchor": "content", - "type": "integer" - } - } - }, - "content": { - "$dynamicAnchor": "content", - "type": "string" - } - } - } - } - }, - "tests": [ - { - "description": "integer property passes", - "data": { "bar-item": { "content": 42 } }, - "valid": true - }, - { - "description": "string property fails", - "data": { "bar-item": { "content": "value" } }, - "valid": false - } - ] - }, - { - "description": "$dynamicRef avoids the root of each schema, but scopes are still registered", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://test.json-schema.org/dynamic-ref-avoids-root-of-each-schema/base", - "$ref": "first#/$defs/stuff", - "$defs": { - "first": { - "$id": "first", - "$defs": { - "stuff": { - "$ref": "second#/$defs/stuff" - }, - "length": { - "$comment": "unused, because there is no $dynamicAnchor here", - "maxLength": 1 - } - } - }, - "second": { - "$id": "second", - "$defs": { - "stuff": { - "$ref": "third#/$defs/stuff" - }, - "length": { - "$dynamicAnchor": "length", - "maxLength": 2 - } - } - }, - "third": { - "$id": "third", - "$defs": { - "stuff": { - "$dynamicRef": "#length" - }, - "length": { - "$dynamicAnchor": "length", - "maxLength": 3 - } - } - } - } - }, - "tests": [ - { - "description": "data is sufficient for schema at second#/$defs/length", - "data": "hi", - "valid": true - }, - { - "description": "data is not sufficient for schema at second#/$defs/length", - "data": "hey", - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/enum.json b/tests/fixtures/json-schema-test-suite/draft2020-12/enum.json deleted file mode 100644 index c8f35eac..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/enum.json +++ /dev/null @@ -1,358 +0,0 @@ -[ - { - "description": "simple enum validation", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "enum": [1, 2, 3] - }, - "tests": [ - { - "description": "one of the enum is valid", - "data": 1, - "valid": true - }, - { - "description": "something else is invalid", - "data": 4, - "valid": false - } - ] - }, - { - "description": "heterogeneous enum validation", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "enum": [6, "foo", [], true, {"foo": 12}] - }, - "tests": [ - { - "description": "one of the enum is valid", - "data": [], - "valid": true - }, - { - "description": "something else is invalid", - "data": null, - "valid": false - }, - { - "description": "objects are deep compared", - "data": {"foo": false}, - "valid": false - }, - { - "description": "valid object matches", - "data": {"foo": 12}, - "valid": true - }, - { - "description": "extra properties in object is invalid", - "data": {"foo": 12, "boo": 42}, - "valid": false - } - ] - }, - { - "description": "heterogeneous enum-with-null validation", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "enum": [6, null] - }, - "tests": [ - { - "description": "null is valid", - "data": null, - "valid": true - }, - { - "description": "number is valid", - "data": 6, - "valid": true - }, - { - "description": "something else is invalid", - "data": "test", - "valid": false - } - ] - }, - { - "description": "enums in properties", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type":"object", - "properties": { - "foo": {"enum":["foo"]}, - "bar": {"enum":["bar"]} - }, - "required": ["bar"] - }, - "tests": [ - { - "description": "both properties are valid", - "data": {"foo":"foo", "bar":"bar"}, - "valid": true - }, - { - "description": "wrong foo value", - "data": {"foo":"foot", "bar":"bar"}, - "valid": false - }, - { - "description": "wrong bar value", - "data": {"foo":"foo", "bar":"bart"}, - "valid": false - }, - { - "description": "missing optional property is valid", - "data": {"bar":"bar"}, - "valid": true - }, - { - "description": "missing required property is invalid", - "data": {"foo":"foo"}, - "valid": false - }, - { - "description": "missing all properties is invalid", - "data": {}, - "valid": false - } - ] - }, - { - "description": "enum with escaped characters", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "enum": ["foo\nbar", "foo\rbar"] - }, - "tests": [ - { - "description": "member 1 is valid", - "data": "foo\nbar", - "valid": true - }, - { - "description": "member 2 is valid", - "data": "foo\rbar", - "valid": true - }, - { - "description": "another string is invalid", - "data": "abc", - "valid": false - } - ] - }, - { - "description": "enum with false does not match 0", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "enum": [false] - }, - "tests": [ - { - "description": "false is valid", - "data": false, - "valid": true - }, - { - "description": "integer zero is invalid", - "data": 0, - "valid": false - }, - { - "description": "float zero is invalid", - "data": 0.0, - "valid": false - } - ] - }, - { - "description": "enum with [false] does not match [0]", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "enum": [[false]] - }, - "tests": [ - { - "description": "[false] is valid", - "data": [false], - "valid": true - }, - { - "description": "[0] is invalid", - "data": [0], - "valid": false - }, - { - "description": "[0.0] is invalid", - "data": [0.0], - "valid": false - } - ] - }, - { - "description": "enum with true does not match 1", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "enum": [true] - }, - "tests": [ - { - "description": "true is valid", - "data": true, - "valid": true - }, - { - "description": "integer one is invalid", - "data": 1, - "valid": false - }, - { - "description": "float one is invalid", - "data": 1.0, - "valid": false - } - ] - }, - { - "description": "enum with [true] does not match [1]", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "enum": [[true]] - }, - "tests": [ - { - "description": "[true] is valid", - "data": [true], - "valid": true - }, - { - "description": "[1] is invalid", - "data": [1], - "valid": false - }, - { - "description": "[1.0] is invalid", - "data": [1.0], - "valid": false - } - ] - }, - { - "description": "enum with 0 does not match false", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "enum": [0] - }, - "tests": [ - { - "description": "false is invalid", - "data": false, - "valid": false - }, - { - "description": "integer zero is valid", - "data": 0, - "valid": true - }, - { - "description": "float zero is valid", - "data": 0.0, - "valid": true - } - ] - }, - { - "description": "enum with [0] does not match [false]", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "enum": [[0]] - }, - "tests": [ - { - "description": "[false] is invalid", - "data": [false], - "valid": false - }, - { - "description": "[0] is valid", - "data": [0], - "valid": true - }, - { - "description": "[0.0] is valid", - "data": [0.0], - "valid": true - } - ] - }, - { - "description": "enum with 1 does not match true", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "enum": [1] - }, - "tests": [ - { - "description": "true is invalid", - "data": true, - "valid": false - }, - { - "description": "integer one is valid", - "data": 1, - "valid": true - }, - { - "description": "float one is valid", - "data": 1.0, - "valid": true - } - ] - }, - { - "description": "enum with [1] does not match [true]", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "enum": [[1]] - }, - "tests": [ - { - "description": "[true] is invalid", - "data": [true], - "valid": false - }, - { - "description": "[1] is valid", - "data": [1], - "valid": true - }, - { - "description": "[1.0] is valid", - "data": [1.0], - "valid": true - } - ] - }, - { - "description": "nul characters in strings", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "enum": [ "hello\u0000there" ] - }, - "tests": [ - { - "description": "match string with nul", - "data": "hello\u0000there", - "valid": true - }, - { - "description": "do not match string lacking nul", - "data": "hellothere", - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/exclusiveMaximum.json b/tests/fixtures/json-schema-test-suite/draft2020-12/exclusiveMaximum.json deleted file mode 100644 index 05db2335..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/exclusiveMaximum.json +++ /dev/null @@ -1,31 +0,0 @@ -[ - { - "description": "exclusiveMaximum validation", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "exclusiveMaximum": 3.0 - }, - "tests": [ - { - "description": "below the exclusiveMaximum is valid", - "data": 2.2, - "valid": true - }, - { - "description": "boundary point is invalid", - "data": 3.0, - "valid": false - }, - { - "description": "above the exclusiveMaximum is invalid", - "data": 3.5, - "valid": false - }, - { - "description": "ignores non-numbers", - "data": "x", - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/exclusiveMinimum.json b/tests/fixtures/json-schema-test-suite/draft2020-12/exclusiveMinimum.json deleted file mode 100644 index 00af9d7f..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/exclusiveMinimum.json +++ /dev/null @@ -1,31 +0,0 @@ -[ - { - "description": "exclusiveMinimum validation", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "exclusiveMinimum": 1.1 - }, - "tests": [ - { - "description": "above the exclusiveMinimum is valid", - "data": 1.2, - "valid": true - }, - { - "description": "boundary point is invalid", - "data": 1.1, - "valid": false - }, - { - "description": "below the exclusiveMinimum is invalid", - "data": 0.6, - "valid": false - }, - { - "description": "ignores non-numbers", - "data": "x", - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/format.json b/tests/fixtures/json-schema-test-suite/draft2020-12/format.json deleted file mode 100644 index 01adcbda..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/format.json +++ /dev/null @@ -1,838 +0,0 @@ -[ - { - "description": "email format", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "email" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "invalid email string is only an annotation by default", - "data": "2962", - "valid": true - } - ] - }, - { - "description": "idn-email format", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "idn-email" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "invalid idn-email string is only an annotation by default", - "data": "2962", - "valid": true - } - ] - }, - { - "description": "regex format", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "regex" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "invalid regex string is only an annotation by default", - "data": "^(abc]", - "valid": true - } - ] - }, - { - "description": "ipv4 format", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "ipv4" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "invalid ipv4 string is only an annotation by default", - "data": "127.0.0.0.1", - "valid": true - } - ] - }, - { - "description": "ipv6 format", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "ipv6" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "invalid ipv6 string is only an annotation by default", - "data": "12345::", - "valid": true - } - ] - }, - { - "description": "idn-hostname format", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "idn-hostname" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "invalid idn-hostname string is only an annotation by default", - "data": "〮실례.테스트", - "valid": true - } - ] - }, - { - "description": "hostname format", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "hostname" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "invalid hostname string is only an annotation by default", - "data": "-a-host-name-that-starts-with--", - "valid": true - } - ] - }, - { - "description": "date format", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "date" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "invalid date string is only an annotation by default", - "data": "06/19/1963", - "valid": true - } - ] - }, - { - "description": "date-time format", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "date-time" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "invalid date-time string is only an annotation by default", - "data": "1990-02-31T15:59:60.123-08:00", - "valid": true - } - ] - }, - { - "description": "time format", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "time" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "invalid time string is only an annotation by default", - "data": "08:30:06 PST", - "valid": true - } - ] - }, - { - "description": "json-pointer format", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "json-pointer" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "invalid json-pointer string is only an annotation by default", - "data": "/foo/bar~", - "valid": true - } - ] - }, - { - "description": "relative-json-pointer format", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "relative-json-pointer" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "invalid relative-json-pointer string is only an annotation by default", - "data": "/foo/bar", - "valid": true - } - ] - }, - { - "description": "iri format", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "iri" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "invalid iri string is only an annotation by default", - "data": "http://2001:0db8:85a3:0000:0000:8a2e:0370:7334", - "valid": true - } - ] - }, - { - "description": "iri-reference format", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "iri-reference" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "invalid iri-reference string is only an annotation by default", - "data": "\\\\WINDOWS\\filëßåré", - "valid": true - } - ] - }, - { - "description": "uri format", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "uri" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "invalid uri string is only an annotation by default", - "data": "//foo.bar/?baz=qux#quux", - "valid": true - } - ] - }, - { - "description": "uri-reference format", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "uri-reference" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "invalid uri-reference string is only an annotation by default", - "data": "\\\\WINDOWS\\fileshare", - "valid": true - } - ] - }, - { - "description": "uri-template format", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "uri-template" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "invalid uri-template string is only an annotation by default", - "data": "http://example.com/dictionary/{term:1}/{term", - "valid": true - } - ] - }, - { - "description": "uuid format", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "uuid" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "invalid uuid string is only an annotation by default", - "data": "2eb8aa08-aa98-11ea-b4aa-73b441d1638", - "valid": true - } - ] - }, - { - "description": "duration format", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "duration" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "invalid duration string is only an annotation by default", - "data": "PT1D", - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/if-then-else.json b/tests/fixtures/json-schema-test-suite/draft2020-12/if-then-else.json deleted file mode 100644 index 1c35d7e6..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/if-then-else.json +++ /dev/null @@ -1,268 +0,0 @@ -[ - { - "description": "ignore if without then or else", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "if": { - "const": 0 - } - }, - "tests": [ - { - "description": "valid when valid against lone if", - "data": 0, - "valid": true - }, - { - "description": "valid when invalid against lone if", - "data": "hello", - "valid": true - } - ] - }, - { - "description": "ignore then without if", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "then": { - "const": 0 - } - }, - "tests": [ - { - "description": "valid when valid against lone then", - "data": 0, - "valid": true - }, - { - "description": "valid when invalid against lone then", - "data": "hello", - "valid": true - } - ] - }, - { - "description": "ignore else without if", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "else": { - "const": 0 - } - }, - "tests": [ - { - "description": "valid when valid against lone else", - "data": 0, - "valid": true - }, - { - "description": "valid when invalid against lone else", - "data": "hello", - "valid": true - } - ] - }, - { - "description": "if and then without else", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "if": { - "exclusiveMaximum": 0 - }, - "then": { - "minimum": -10 - } - }, - "tests": [ - { - "description": "valid through then", - "data": -1, - "valid": true - }, - { - "description": "invalid through then", - "data": -100, - "valid": false - }, - { - "description": "valid when if test fails", - "data": 3, - "valid": true - } - ] - }, - { - "description": "if and else without then", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "if": { - "exclusiveMaximum": 0 - }, - "else": { - "multipleOf": 2 - } - }, - "tests": [ - { - "description": "valid when if test passes", - "data": -1, - "valid": true - }, - { - "description": "valid through else", - "data": 4, - "valid": true - }, - { - "description": "invalid through else", - "data": 3, - "valid": false - } - ] - }, - { - "description": "validate against correct branch, then vs else", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "if": { - "exclusiveMaximum": 0 - }, - "then": { - "minimum": -10 - }, - "else": { - "multipleOf": 2 - } - }, - "tests": [ - { - "description": "valid through then", - "data": -1, - "valid": true - }, - { - "description": "invalid through then", - "data": -100, - "valid": false - }, - { - "description": "valid through else", - "data": 4, - "valid": true - }, - { - "description": "invalid through else", - "data": 3, - "valid": false - } - ] - }, - { - "description": "non-interference across combined schemas", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [ - { - "if": { - "exclusiveMaximum": 0 - } - }, - { - "then": { - "minimum": -10 - } - }, - { - "else": { - "multipleOf": 2 - } - } - ] - }, - "tests": [ - { - "description": "valid, but would have been invalid through then", - "data": -100, - "valid": true - }, - { - "description": "valid, but would have been invalid through else", - "data": 3, - "valid": true - } - ] - }, - { - "description": "if with boolean schema true", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "if": true, - "then": { "const": "then" }, - "else": { "const": "else" } - }, - "tests": [ - { - "description": "boolean schema true in if always chooses the then path (valid)", - "data": "then", - "valid": true - }, - { - "description": "boolean schema true in if always chooses the then path (invalid)", - "data": "else", - "valid": false - } - ] - }, - { - "description": "if with boolean schema false", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "if": false, - "then": { "const": "then" }, - "else": { "const": "else" } - }, - "tests": [ - { - "description": "boolean schema false in if always chooses the else path (invalid)", - "data": "then", - "valid": false - }, - { - "description": "boolean schema false in if always chooses the else path (valid)", - "data": "else", - "valid": true - } - ] - }, - { - "description": "if appears at the end when serialized (keyword processing sequence)", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "then": { "const": "yes" }, - "else": { "const": "other" }, - "if": { "maxLength": 4 } - }, - "tests": [ - { - "description": "yes redirects to then and passes", - "data": "yes", - "valid": true - }, - { - "description": "other redirects to else and passes", - "data": "other", - "valid": true - }, - { - "description": "no redirects to then and fails", - "data": "no", - "valid": false - }, - { - "description": "invalid redirects to else and fails", - "data": "invalid", - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/infinite-loop-detection.json b/tests/fixtures/json-schema-test-suite/draft2020-12/infinite-loop-detection.json deleted file mode 100644 index 46f157a3..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/infinite-loop-detection.json +++ /dev/null @@ -1,37 +0,0 @@ -[ - { - "description": "evaluating the same schema location against the same data location twice is not a sign of an infinite loop", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$defs": { - "int": { "type": "integer" } - }, - "allOf": [ - { - "properties": { - "foo": { - "$ref": "#/$defs/int" - } - } - }, - { - "additionalProperties": { - "$ref": "#/$defs/int" - } - } - ] - }, - "tests": [ - { - "description": "passing case", - "data": { "foo": 1 }, - "valid": true - }, - { - "description": "failing case", - "data": { "foo": "a string" }, - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/items.json b/tests/fixtures/json-schema-test-suite/draft2020-12/items.json deleted file mode 100644 index 6a3e1cf2..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/items.json +++ /dev/null @@ -1,304 +0,0 @@ -[ - { - "description": "a schema given for items", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "items": {"type": "integer"} - }, - "tests": [ - { - "description": "valid items", - "data": [ 1, 2, 3 ], - "valid": true - }, - { - "description": "wrong type of items", - "data": [1, "x"], - "valid": false - }, - { - "description": "ignores non-arrays", - "data": {"foo" : "bar"}, - "valid": true - }, - { - "description": "JavaScript pseudo-array is valid", - "data": { - "0": "invalid", - "length": 1 - }, - "valid": true - } - ] - }, - { - "description": "items with boolean schema (true)", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "items": true - }, - "tests": [ - { - "description": "any array is valid", - "data": [ 1, "foo", true ], - "valid": true - }, - { - "description": "empty array is valid", - "data": [], - "valid": true - } - ] - }, - { - "description": "items with boolean schema (false)", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "items": false - }, - "tests": [ - { - "description": "any non-empty array is invalid", - "data": [ 1, "foo", true ], - "valid": false - }, - { - "description": "empty array is valid", - "data": [], - "valid": true - } - ] - }, - { - "description": "items and subitems", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$defs": { - "item": { - "type": "array", - "items": false, - "prefixItems": [ - { "$ref": "#/$defs/sub-item" }, - { "$ref": "#/$defs/sub-item" } - ] - }, - "sub-item": { - "type": "object", - "required": ["foo"] - } - }, - "type": "array", - "items": false, - "prefixItems": [ - { "$ref": "#/$defs/item" }, - { "$ref": "#/$defs/item" }, - { "$ref": "#/$defs/item" } - ] - }, - "tests": [ - { - "description": "valid items", - "data": [ - [ {"foo": null}, {"foo": null} ], - [ {"foo": null}, {"foo": null} ], - [ {"foo": null}, {"foo": null} ] - ], - "valid": true - }, - { - "description": "too many items", - "data": [ - [ {"foo": null}, {"foo": null} ], - [ {"foo": null}, {"foo": null} ], - [ {"foo": null}, {"foo": null} ], - [ {"foo": null}, {"foo": null} ] - ], - "valid": false - }, - { - "description": "too many sub-items", - "data": [ - [ {"foo": null}, {"foo": null}, {"foo": null} ], - [ {"foo": null}, {"foo": null} ], - [ {"foo": null}, {"foo": null} ] - ], - "valid": false - }, - { - "description": "wrong item", - "data": [ - {"foo": null}, - [ {"foo": null}, {"foo": null} ], - [ {"foo": null}, {"foo": null} ] - ], - "valid": false - }, - { - "description": "wrong sub-item", - "data": [ - [ {}, {"foo": null} ], - [ {"foo": null}, {"foo": null} ], - [ {"foo": null}, {"foo": null} ] - ], - "valid": false - }, - { - "description": "fewer items is valid", - "data": [ - [ {"foo": null} ], - [ {"foo": null} ] - ], - "valid": true - } - ] - }, - { - "description": "nested items", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "array", - "items": { - "type": "array", - "items": { - "type": "array", - "items": { - "type": "array", - "items": { - "type": "number" - } - } - } - } - }, - "tests": [ - { - "description": "valid nested array", - "data": [[[[1]], [[2],[3]]], [[[4], [5], [6]]]], - "valid": true - }, - { - "description": "nested array with invalid type", - "data": [[[["1"]], [[2],[3]]], [[[4], [5], [6]]]], - "valid": false - }, - { - "description": "not deep enough", - "data": [[[1], [2],[3]], [[4], [5], [6]]], - "valid": false - } - ] - }, - { - "description": "prefixItems with no additional items allowed", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "prefixItems": [{}, {}, {}], - "items": false - }, - "tests": [ - { - "description": "empty array", - "data": [ ], - "valid": true - }, - { - "description": "fewer number of items present (1)", - "data": [ 1 ], - "valid": true - }, - { - "description": "fewer number of items present (2)", - "data": [ 1, 2 ], - "valid": true - }, - { - "description": "equal number of items present", - "data": [ 1, 2, 3 ], - "valid": true - }, - { - "description": "additional items are not permitted", - "data": [ 1, 2, 3, 4 ], - "valid": false - } - ] - }, - { - "description": "items does not look in applicators, valid case", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [ - { "prefixItems": [ { "minimum": 3 } ] } - ], - "items": { "minimum": 5 } - }, - "tests": [ - { - "description": "prefixItems in allOf does not constrain items, invalid case", - "data": [ 3, 5 ], - "valid": false - }, - { - "description": "prefixItems in allOf does not constrain items, valid case", - "data": [ 5, 5 ], - "valid": true - } - ] - }, - { - "description": "prefixItems validation adjusts the starting index for items", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "prefixItems": [ { "type": "string" } ], - "items": { "type": "integer" } - }, - "tests": [ - { - "description": "valid items", - "data": [ "x", 2, 3 ], - "valid": true - }, - { - "description": "wrong type of second item", - "data": [ "x", "y" ], - "valid": false - } - ] - }, - { - "description": "items with heterogeneous array", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "prefixItems": [{}], - "items": false - }, - "tests": [ - { - "description": "heterogeneous invalid instance", - "data": [ "foo", "bar", 37 ], - "valid": false - }, - { - "description": "valid instance", - "data": [ null ], - "valid": true - } - ] - }, - { - "description": "items with null instance elements", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "items": { - "type": "null" - } - }, - "tests": [ - { - "description": "allows null elements", - "data": [ null ], - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/maxContains.json b/tests/fixtures/json-schema-test-suite/draft2020-12/maxContains.json deleted file mode 100644 index 8cd3ca74..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/maxContains.json +++ /dev/null @@ -1,102 +0,0 @@ -[ - { - "description": "maxContains without contains is ignored", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "maxContains": 1 - }, - "tests": [ - { - "description": "one item valid against lone maxContains", - "data": [ 1 ], - "valid": true - }, - { - "description": "two items still valid against lone maxContains", - "data": [ 1, 2 ], - "valid": true - } - ] - }, - { - "description": "maxContains with contains", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "contains": {"const": 1}, - "maxContains": 1 - }, - "tests": [ - { - "description": "empty data", - "data": [ ], - "valid": false - }, - { - "description": "all elements match, valid maxContains", - "data": [ 1 ], - "valid": true - }, - { - "description": "all elements match, invalid maxContains", - "data": [ 1, 1 ], - "valid": false - }, - { - "description": "some elements match, valid maxContains", - "data": [ 1, 2 ], - "valid": true - }, - { - "description": "some elements match, invalid maxContains", - "data": [ 1, 2, 1 ], - "valid": false - } - ] - }, - { - "description": "maxContains with contains, value with a decimal", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "contains": {"const": 1}, - "maxContains": 1.0 - }, - "tests": [ - { - "description": "one element matches, valid maxContains", - "data": [ 1 ], - "valid": true - }, - { - "description": "too many elements match, invalid maxContains", - "data": [ 1, 1 ], - "valid": false - } - ] - }, - { - "description": "minContains < maxContains", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "contains": {"const": 1}, - "minContains": 1, - "maxContains": 3 - }, - "tests": [ - { - "description": "actual < minContains < maxContains", - "data": [ ], - "valid": false - }, - { - "description": "minContains < actual < maxContains", - "data": [ 1, 1 ], - "valid": true - }, - { - "description": "minContains < maxContains < actual", - "data": [ 1, 1, 1, 1 ], - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/maxItems.json b/tests/fixtures/json-schema-test-suite/draft2020-12/maxItems.json deleted file mode 100644 index f6a6b7c9..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/maxItems.json +++ /dev/null @@ -1,50 +0,0 @@ -[ - { - "description": "maxItems validation", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "maxItems": 2 - }, - "tests": [ - { - "description": "shorter is valid", - "data": [1], - "valid": true - }, - { - "description": "exact length is valid", - "data": [1, 2], - "valid": true - }, - { - "description": "too long is invalid", - "data": [1, 2, 3], - "valid": false - }, - { - "description": "ignores non-arrays", - "data": "foobar", - "valid": true - } - ] - }, - { - "description": "maxItems validation with a decimal", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "maxItems": 2.0 - }, - "tests": [ - { - "description": "shorter is valid", - "data": [1], - "valid": true - }, - { - "description": "too long is invalid", - "data": [1, 2, 3], - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/maxLength.json b/tests/fixtures/json-schema-test-suite/draft2020-12/maxLength.json deleted file mode 100644 index 7462726d..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/maxLength.json +++ /dev/null @@ -1,55 +0,0 @@ -[ - { - "description": "maxLength validation", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "maxLength": 2 - }, - "tests": [ - { - "description": "shorter is valid", - "data": "f", - "valid": true - }, - { - "description": "exact length is valid", - "data": "fo", - "valid": true - }, - { - "description": "too long is invalid", - "data": "foo", - "valid": false - }, - { - "description": "ignores non-strings", - "data": 100, - "valid": true - }, - { - "description": "two graphemes is long enough", - "data": "\uD83D\uDCA9\uD83D\uDCA9", - "valid": true - } - ] - }, - { - "description": "maxLength validation with a decimal", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "maxLength": 2.0 - }, - "tests": [ - { - "description": "shorter is valid", - "data": "f", - "valid": true - }, - { - "description": "too long is invalid", - "data": "foo", - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/maxProperties.json b/tests/fixtures/json-schema-test-suite/draft2020-12/maxProperties.json deleted file mode 100644 index 73ae7316..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/maxProperties.json +++ /dev/null @@ -1,79 +0,0 @@ -[ - { - "description": "maxProperties validation", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "maxProperties": 2 - }, - "tests": [ - { - "description": "shorter is valid", - "data": {"foo": 1}, - "valid": true - }, - { - "description": "exact length is valid", - "data": {"foo": 1, "bar": 2}, - "valid": true - }, - { - "description": "too long is invalid", - "data": {"foo": 1, "bar": 2, "baz": 3}, - "valid": false - }, - { - "description": "ignores arrays", - "data": [1, 2, 3], - "valid": true - }, - { - "description": "ignores strings", - "data": "foobar", - "valid": true - }, - { - "description": "ignores other non-objects", - "data": 12, - "valid": true - } - ] - }, - { - "description": "maxProperties validation with a decimal", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "maxProperties": 2.0 - }, - "tests": [ - { - "description": "shorter is valid", - "data": {"foo": 1}, - "valid": true - }, - { - "description": "too long is invalid", - "data": {"foo": 1, "bar": 2, "baz": 3}, - "valid": false - } - ] - }, - { - "description": "maxProperties = 0 means the object is empty", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "maxProperties": 0 - }, - "tests": [ - { - "description": "no properties is valid", - "data": {}, - "valid": true - }, - { - "description": "one property is invalid", - "data": { "foo": 1 }, - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/maximum.json b/tests/fixtures/json-schema-test-suite/draft2020-12/maximum.json deleted file mode 100644 index b99a541e..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/maximum.json +++ /dev/null @@ -1,60 +0,0 @@ -[ - { - "description": "maximum validation", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "maximum": 3.0 - }, - "tests": [ - { - "description": "below the maximum is valid", - "data": 2.6, - "valid": true - }, - { - "description": "boundary point is valid", - "data": 3.0, - "valid": true - }, - { - "description": "above the maximum is invalid", - "data": 3.5, - "valid": false - }, - { - "description": "ignores non-numbers", - "data": "x", - "valid": true - } - ] - }, - { - "description": "maximum validation with unsigned integer", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "maximum": 300 - }, - "tests": [ - { - "description": "below the maximum is invalid", - "data": 299.97, - "valid": true - }, - { - "description": "boundary point integer is valid", - "data": 300, - "valid": true - }, - { - "description": "boundary point float is valid", - "data": 300.00, - "valid": true - }, - { - "description": "above the maximum is invalid", - "data": 300.5, - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/minContains.json b/tests/fixtures/json-schema-test-suite/draft2020-12/minContains.json deleted file mode 100644 index ee72d7d6..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/minContains.json +++ /dev/null @@ -1,224 +0,0 @@ -[ - { - "description": "minContains without contains is ignored", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "minContains": 1 - }, - "tests": [ - { - "description": "one item valid against lone minContains", - "data": [ 1 ], - "valid": true - }, - { - "description": "zero items still valid against lone minContains", - "data": [], - "valid": true - } - ] - }, - { - "description": "minContains=1 with contains", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "contains": {"const": 1}, - "minContains": 1 - }, - "tests": [ - { - "description": "empty data", - "data": [ ], - "valid": false - }, - { - "description": "no elements match", - "data": [ 2 ], - "valid": false - }, - { - "description": "single element matches, valid minContains", - "data": [ 1 ], - "valid": true - }, - { - "description": "some elements match, valid minContains", - "data": [ 1, 2 ], - "valid": true - }, - { - "description": "all elements match, valid minContains", - "data": [ 1, 1 ], - "valid": true - } - ] - }, - { - "description": "minContains=2 with contains", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "contains": {"const": 1}, - "minContains": 2 - }, - "tests": [ - { - "description": "empty data", - "data": [ ], - "valid": false - }, - { - "description": "all elements match, invalid minContains", - "data": [ 1 ], - "valid": false - }, - { - "description": "some elements match, invalid minContains", - "data": [ 1, 2 ], - "valid": false - }, - { - "description": "all elements match, valid minContains (exactly as needed)", - "data": [ 1, 1 ], - "valid": true - }, - { - "description": "all elements match, valid minContains (more than needed)", - "data": [ 1, 1, 1 ], - "valid": true - }, - { - "description": "some elements match, valid minContains", - "data": [ 1, 2, 1 ], - "valid": true - } - ] - }, - { - "description": "minContains=2 with contains with a decimal value", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "contains": {"const": 1}, - "minContains": 2.0 - }, - "tests": [ - { - "description": "one element matches, invalid minContains", - "data": [ 1 ], - "valid": false - }, - { - "description": "both elements match, valid minContains", - "data": [ 1, 1 ], - "valid": true - } - ] - }, - { - "description": "maxContains = minContains", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "contains": {"const": 1}, - "maxContains": 2, - "minContains": 2 - }, - "tests": [ - { - "description": "empty data", - "data": [ ], - "valid": false - }, - { - "description": "all elements match, invalid minContains", - "data": [ 1 ], - "valid": false - }, - { - "description": "all elements match, invalid maxContains", - "data": [ 1, 1, 1 ], - "valid": false - }, - { - "description": "all elements match, valid maxContains and minContains", - "data": [ 1, 1 ], - "valid": true - } - ] - }, - { - "description": "maxContains < minContains", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "contains": {"const": 1}, - "maxContains": 1, - "minContains": 3 - }, - "tests": [ - { - "description": "empty data", - "data": [ ], - "valid": false - }, - { - "description": "invalid minContains", - "data": [ 1 ], - "valid": false - }, - { - "description": "invalid maxContains", - "data": [ 1, 1, 1 ], - "valid": false - }, - { - "description": "invalid maxContains and minContains", - "data": [ 1, 1 ], - "valid": false - } - ] - }, - { - "description": "minContains = 0", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "contains": {"const": 1}, - "minContains": 0 - }, - "tests": [ - { - "description": "empty data", - "data": [ ], - "valid": true - }, - { - "description": "minContains = 0 makes contains always pass", - "data": [ 2 ], - "valid": true - } - ] - }, - { - "description": "minContains = 0 with maxContains", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "contains": {"const": 1}, - "minContains": 0, - "maxContains": 1 - }, - "tests": [ - { - "description": "empty data", - "data": [ ], - "valid": true - }, - { - "description": "not more than maxContains", - "data": [ 1 ], - "valid": true - }, - { - "description": "too many", - "data": [ 1, 1 ], - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/minItems.json b/tests/fixtures/json-schema-test-suite/draft2020-12/minItems.json deleted file mode 100644 index 9d6a8b6d..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/minItems.json +++ /dev/null @@ -1,50 +0,0 @@ -[ - { - "description": "minItems validation", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "minItems": 1 - }, - "tests": [ - { - "description": "longer is valid", - "data": [1, 2], - "valid": true - }, - { - "description": "exact length is valid", - "data": [1], - "valid": true - }, - { - "description": "too short is invalid", - "data": [], - "valid": false - }, - { - "description": "ignores non-arrays", - "data": "", - "valid": true - } - ] - }, - { - "description": "minItems validation with a decimal", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "minItems": 1.0 - }, - "tests": [ - { - "description": "longer is valid", - "data": [1, 2], - "valid": true - }, - { - "description": "too short is invalid", - "data": [], - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/minLength.json b/tests/fixtures/json-schema-test-suite/draft2020-12/minLength.json deleted file mode 100644 index 5076c5a9..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/minLength.json +++ /dev/null @@ -1,55 +0,0 @@ -[ - { - "description": "minLength validation", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "minLength": 2 - }, - "tests": [ - { - "description": "longer is valid", - "data": "foo", - "valid": true - }, - { - "description": "exact length is valid", - "data": "fo", - "valid": true - }, - { - "description": "too short is invalid", - "data": "f", - "valid": false - }, - { - "description": "ignores non-strings", - "data": 1, - "valid": true - }, - { - "description": "one grapheme is not long enough", - "data": "\uD83D\uDCA9", - "valid": false - } - ] - }, - { - "description": "minLength validation with a decimal", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "minLength": 2.0 - }, - "tests": [ - { - "description": "longer is valid", - "data": "foo", - "valid": true - }, - { - "description": "too short is invalid", - "data": "f", - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/minProperties.json b/tests/fixtures/json-schema-test-suite/draft2020-12/minProperties.json deleted file mode 100644 index a753ad35..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/minProperties.json +++ /dev/null @@ -1,60 +0,0 @@ -[ - { - "description": "minProperties validation", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "minProperties": 1 - }, - "tests": [ - { - "description": "longer is valid", - "data": {"foo": 1, "bar": 2}, - "valid": true - }, - { - "description": "exact length is valid", - "data": {"foo": 1}, - "valid": true - }, - { - "description": "too short is invalid", - "data": {}, - "valid": false - }, - { - "description": "ignores arrays", - "data": [], - "valid": true - }, - { - "description": "ignores strings", - "data": "", - "valid": true - }, - { - "description": "ignores other non-objects", - "data": 12, - "valid": true - } - ] - }, - { - "description": "minProperties validation with a decimal", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "minProperties": 1.0 - }, - "tests": [ - { - "description": "longer is valid", - "data": {"foo": 1, "bar": 2}, - "valid": true - }, - { - "description": "too short is invalid", - "data": {}, - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/minimum.json b/tests/fixtures/json-schema-test-suite/draft2020-12/minimum.json deleted file mode 100644 index dc440527..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/minimum.json +++ /dev/null @@ -1,75 +0,0 @@ -[ - { - "description": "minimum validation", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "minimum": 1.1 - }, - "tests": [ - { - "description": "above the minimum is valid", - "data": 2.6, - "valid": true - }, - { - "description": "boundary point is valid", - "data": 1.1, - "valid": true - }, - { - "description": "below the minimum is invalid", - "data": 0.6, - "valid": false - }, - { - "description": "ignores non-numbers", - "data": "x", - "valid": true - } - ] - }, - { - "description": "minimum validation with signed integer", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "minimum": -2 - }, - "tests": [ - { - "description": "negative above the minimum is valid", - "data": -1, - "valid": true - }, - { - "description": "positive above the minimum is valid", - "data": 0, - "valid": true - }, - { - "description": "boundary point is valid", - "data": -2, - "valid": true - }, - { - "description": "boundary point with float is valid", - "data": -2.0, - "valid": true - }, - { - "description": "float below the minimum is invalid", - "data": -2.0001, - "valid": false - }, - { - "description": "int below the minimum is invalid", - "data": -3, - "valid": false - }, - { - "description": "ignores non-numbers", - "data": "x", - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/multipleOf.json b/tests/fixtures/json-schema-test-suite/draft2020-12/multipleOf.json deleted file mode 100644 index 92d6979b..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/multipleOf.json +++ /dev/null @@ -1,97 +0,0 @@ -[ - { - "description": "by int", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "multipleOf": 2 - }, - "tests": [ - { - "description": "int by int", - "data": 10, - "valid": true - }, - { - "description": "int by int fail", - "data": 7, - "valid": false - }, - { - "description": "ignores non-numbers", - "data": "foo", - "valid": true - } - ] - }, - { - "description": "by number", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "multipleOf": 1.5 - }, - "tests": [ - { - "description": "zero is multiple of anything", - "data": 0, - "valid": true - }, - { - "description": "4.5 is multiple of 1.5", - "data": 4.5, - "valid": true - }, - { - "description": "35 is not multiple of 1.5", - "data": 35, - "valid": false - } - ] - }, - { - "description": "by small number", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "multipleOf": 0.0001 - }, - "tests": [ - { - "description": "0.0075 is multiple of 0.0001", - "data": 0.0075, - "valid": true - }, - { - "description": "0.00751 is not multiple of 0.0001", - "data": 0.00751, - "valid": false - } - ] - }, - { - "description": "float division = inf", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "integer", "multipleOf": 0.123456789 - }, - "tests": [ - { - "description": "always invalid, but naive implementations may raise an overflow error", - "data": 1e308, - "valid": false - } - ] - }, - { - "description": "small multiple of large integer", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "integer", "multipleOf": 1e-8 - }, - "tests": [ - { - "description": "any integer is a multiple of 1e-8", - "data": 12391239123, - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/not.json b/tests/fixtures/json-schema-test-suite/draft2020-12/not.json deleted file mode 100644 index d0f2b6e8..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/not.json +++ /dev/null @@ -1,301 +0,0 @@ -[ - { - "description": "not", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "not": {"type": "integer"} - }, - "tests": [ - { - "description": "allowed", - "data": "foo", - "valid": true - }, - { - "description": "disallowed", - "data": 1, - "valid": false - } - ] - }, - { - "description": "not multiple types", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "not": {"type": ["integer", "boolean"]} - }, - "tests": [ - { - "description": "valid", - "data": "foo", - "valid": true - }, - { - "description": "mismatch", - "data": 1, - "valid": false - }, - { - "description": "other mismatch", - "data": true, - "valid": false - } - ] - }, - { - "description": "not more complex schema", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "not": { - "type": "object", - "properties": { - "foo": { - "type": "string" - } - } - } - }, - "tests": [ - { - "description": "match", - "data": 1, - "valid": true - }, - { - "description": "other match", - "data": {"foo": 1}, - "valid": true - }, - { - "description": "mismatch", - "data": {"foo": "bar"}, - "valid": false - } - ] - }, - { - "description": "forbidden property", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": { - "not": {} - } - } - }, - "tests": [ - { - "description": "property present", - "data": {"foo": 1, "bar": 2}, - "valid": false - }, - { - "description": "property absent", - "data": {"bar": 1, "baz": 2}, - "valid": true - } - ] - }, - { - "description": "forbid everything with empty schema", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "not": {} - }, - "tests": [ - { - "description": "number is invalid", - "data": 1, - "valid": false - }, - { - "description": "string is invalid", - "data": "foo", - "valid": false - }, - { - "description": "boolean true is invalid", - "data": true, - "valid": false - }, - { - "description": "boolean false is invalid", - "data": false, - "valid": false - }, - { - "description": "null is invalid", - "data": null, - "valid": false - }, - { - "description": "object is invalid", - "data": {"foo": "bar"}, - "valid": false - }, - { - "description": "empty object is invalid", - "data": {}, - "valid": false - }, - { - "description": "array is invalid", - "data": ["foo"], - "valid": false - }, - { - "description": "empty array is invalid", - "data": [], - "valid": false - } - ] - }, - { - "description": "forbid everything with boolean schema true", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "not": true - }, - "tests": [ - { - "description": "number is invalid", - "data": 1, - "valid": false - }, - { - "description": "string is invalid", - "data": "foo", - "valid": false - }, - { - "description": "boolean true is invalid", - "data": true, - "valid": false - }, - { - "description": "boolean false is invalid", - "data": false, - "valid": false - }, - { - "description": "null is invalid", - "data": null, - "valid": false - }, - { - "description": "object is invalid", - "data": {"foo": "bar"}, - "valid": false - }, - { - "description": "empty object is invalid", - "data": {}, - "valid": false - }, - { - "description": "array is invalid", - "data": ["foo"], - "valid": false - }, - { - "description": "empty array is invalid", - "data": [], - "valid": false - } - ] - }, - { - "description": "allow everything with boolean schema false", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "not": false - }, - "tests": [ - { - "description": "number is valid", - "data": 1, - "valid": true - }, - { - "description": "string is valid", - "data": "foo", - "valid": true - }, - { - "description": "boolean true is valid", - "data": true, - "valid": true - }, - { - "description": "boolean false is valid", - "data": false, - "valid": true - }, - { - "description": "null is valid", - "data": null, - "valid": true - }, - { - "description": "object is valid", - "data": {"foo": "bar"}, - "valid": true - }, - { - "description": "empty object is valid", - "data": {}, - "valid": true - }, - { - "description": "array is valid", - "data": ["foo"], - "valid": true - }, - { - "description": "empty array is valid", - "data": [], - "valid": true - } - ] - }, - { - "description": "double negation", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "not": { "not": {} } - }, - "tests": [ - { - "description": "any value is valid", - "data": "foo", - "valid": true - } - ] - }, - { - "description": "collect annotations inside a 'not', even if collection is disabled", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "not": { - "$comment": "this subschema must still produce annotations internally, even though the 'not' will ultimately discard them", - "anyOf": [ - true, - { "properties": { "foo": true } } - ], - "unevaluatedProperties": false - } - }, - "tests": [ - { - "description": "unevaluated property", - "data": { "bar": 1 }, - "valid": true - }, - { - "description": "annotations are still collected inside a 'not'", - "data": { "foo": 1 }, - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/oneOf.json b/tests/fixtures/json-schema-test-suite/draft2020-12/oneOf.json deleted file mode 100644 index 7a7c7ffe..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/oneOf.json +++ /dev/null @@ -1,293 +0,0 @@ -[ - { - "description": "oneOf", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "oneOf": [ - { - "type": "integer" - }, - { - "minimum": 2 - } - ] - }, - "tests": [ - { - "description": "first oneOf valid", - "data": 1, - "valid": true - }, - { - "description": "second oneOf valid", - "data": 2.5, - "valid": true - }, - { - "description": "both oneOf valid", - "data": 3, - "valid": false - }, - { - "description": "neither oneOf valid", - "data": 1.5, - "valid": false - } - ] - }, - { - "description": "oneOf with base schema", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "string", - "oneOf" : [ - { - "minLength": 2 - }, - { - "maxLength": 4 - } - ] - }, - "tests": [ - { - "description": "mismatch base schema", - "data": 3, - "valid": false - }, - { - "description": "one oneOf valid", - "data": "foobar", - "valid": true - }, - { - "description": "both oneOf valid", - "data": "foo", - "valid": false - } - ] - }, - { - "description": "oneOf with boolean schemas, all true", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "oneOf": [true, true, true] - }, - "tests": [ - { - "description": "any value is invalid", - "data": "foo", - "valid": false - } - ] - }, - { - "description": "oneOf with boolean schemas, one true", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "oneOf": [true, false, false] - }, - "tests": [ - { - "description": "any value is valid", - "data": "foo", - "valid": true - } - ] - }, - { - "description": "oneOf with boolean schemas, more than one true", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "oneOf": [true, true, false] - }, - "tests": [ - { - "description": "any value is invalid", - "data": "foo", - "valid": false - } - ] - }, - { - "description": "oneOf with boolean schemas, all false", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "oneOf": [false, false, false] - }, - "tests": [ - { - "description": "any value is invalid", - "data": "foo", - "valid": false - } - ] - }, - { - "description": "oneOf complex types", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "oneOf": [ - { - "properties": { - "bar": {"type": "integer"} - }, - "required": ["bar"] - }, - { - "properties": { - "foo": {"type": "string"} - }, - "required": ["foo"] - } - ] - }, - "tests": [ - { - "description": "first oneOf valid (complex)", - "data": {"bar": 2}, - "valid": true - }, - { - "description": "second oneOf valid (complex)", - "data": {"foo": "baz"}, - "valid": true - }, - { - "description": "both oneOf valid (complex)", - "data": {"foo": "baz", "bar": 2}, - "valid": false - }, - { - "description": "neither oneOf valid (complex)", - "data": {"foo": 2, "bar": "quux"}, - "valid": false - } - ] - }, - { - "description": "oneOf with empty schema", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "oneOf": [ - { "type": "number" }, - {} - ] - }, - "tests": [ - { - "description": "one valid - valid", - "data": "foo", - "valid": true - }, - { - "description": "both valid - invalid", - "data": 123, - "valid": false - } - ] - }, - { - "description": "oneOf with required", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "oneOf": [ - { "required": ["foo", "bar"] }, - { "required": ["foo", "baz"] } - ] - }, - "tests": [ - { - "description": "both invalid - invalid", - "data": {"bar": 2}, - "valid": false - }, - { - "description": "first valid - valid", - "data": {"foo": 1, "bar": 2}, - "valid": true - }, - { - "description": "second valid - valid", - "data": {"foo": 1, "baz": 3}, - "valid": true - }, - { - "description": "both valid - invalid", - "data": {"foo": 1, "bar": 2, "baz" : 3}, - "valid": false - } - ] - }, - { - "description": "oneOf with missing optional property", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "oneOf": [ - { - "properties": { - "bar": true, - "baz": true - }, - "required": ["bar"] - }, - { - "properties": { - "foo": true - }, - "required": ["foo"] - } - ] - }, - "tests": [ - { - "description": "first oneOf valid", - "data": {"bar": 8}, - "valid": true - }, - { - "description": "second oneOf valid", - "data": {"foo": "foo"}, - "valid": true - }, - { - "description": "both oneOf valid", - "data": {"foo": "foo", "bar": 8}, - "valid": false - }, - { - "description": "neither oneOf valid", - "data": {"baz": "quux"}, - "valid": false - } - ] - }, - { - "description": "nested oneOf, to check validation semantics", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "oneOf": [ - { - "oneOf": [ - { - "type": "null" - } - ] - } - ] - }, - "tests": [ - { - "description": "null is valid", - "data": null, - "valid": true - }, - { - "description": "anything non-null is invalid", - "data": 123, - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/anchor.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/anchor.json deleted file mode 100644 index 6d6713be..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/anchor.json +++ /dev/null @@ -1,60 +0,0 @@ -[ - { - "description": "$anchor inside an enum is not a real identifier", - "comment": "the implementation must not be confused by an $anchor buried in the enum", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$defs": { - "anchor_in_enum": { - "enum": [ - { - "$anchor": "my_anchor", - "type": "null" - } - ] - }, - "real_identifier_in_schema": { - "$anchor": "my_anchor", - "type": "string" - }, - "zzz_anchor_in_const": { - "const": { - "$anchor": "my_anchor", - "type": "null" - } - } - }, - "anyOf": [ - { "$ref": "#/$defs/anchor_in_enum" }, - { "$ref": "#my_anchor" } - ] - }, - "tests": [ - { - "description": "exact match to enum, and type matches", - "data": { - "$anchor": "my_anchor", - "type": "null" - }, - "valid": true - }, - { - "description": "in implementations that strip $anchor, this may match either $def", - "data": { - "type": "null" - }, - "valid": false - }, - { - "description": "match $ref to $anchor", - "data": "a string to match #/$defs/anchor_in_enum", - "valid": true - }, - { - "description": "no match on enum or $ref to $anchor", - "data": 1, - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/bignum.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/bignum.json deleted file mode 100644 index d69b29e8..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/bignum.json +++ /dev/null @@ -1,110 +0,0 @@ -[ - { - "description": "integer", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "integer" - }, - "tests": [ - { - "description": "a bignum is an integer", - "data": 12345678910111213141516171819202122232425262728293031, - "valid": true - }, - { - "description": "a negative bignum is an integer", - "data": -12345678910111213141516171819202122232425262728293031, - "valid": true - } - ] - }, - { - "description": "number", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "number" - }, - "tests": [ - { - "description": "a bignum is a number", - "data": 98249283749234923498293171823948729348710298301928331, - "valid": true - }, - { - "description": "a negative bignum is a number", - "data": -98249283749234923498293171823948729348710298301928331, - "valid": true - } - ] - }, - { - "description": "string", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "string" - }, - "tests": [ - { - "description": "a bignum is not a string", - "data": 98249283749234923498293171823948729348710298301928331, - "valid": false - } - ] - }, - { - "description": "maximum integer comparison", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "maximum": 18446744073709551615 - }, - "tests": [ - { - "description": "comparison works for high numbers", - "data": 18446744073709551600, - "valid": true - } - ] - }, - { - "description": "float comparison with high precision", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "exclusiveMaximum": 972783798187987123879878123.18878137 - }, - "tests": [ - { - "description": "comparison works for high numbers", - "data": 972783798187987123879878123.188781371, - "valid": false - } - ] - }, - { - "description": "minimum integer comparison", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "minimum": -18446744073709551615 - }, - "tests": [ - { - "description": "comparison works for very negative numbers", - "data": -18446744073709551600, - "valid": true - } - ] - }, - { - "description": "float comparison with high precision on negative numbers", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "exclusiveMinimum": -972783798187987123879878123.18878137 - }, - "tests": [ - { - "description": "comparison works for very negative numbers", - "data": -972783798187987123879878123.188781371, - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/cross-draft.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/cross-draft.json deleted file mode 100644 index 5113bd64..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/cross-draft.json +++ /dev/null @@ -1,18 +0,0 @@ -[ - { - "description": "refs to historic drafts are processed as historic drafts", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "array", - "$ref": "http://localhost:1234/draft2019-09/ignore-prefixItems.json" - }, - "tests": [ - { - "description": "first item not a string is valid", - "comment": "if the implementation is not processing the $ref as a 2019-09 schema, this test will fail", - "data": [1, 2, 3], - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/dependencies-compatibility.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/dependencies-compatibility.json deleted file mode 100644 index 47d5bd79..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/dependencies-compatibility.json +++ /dev/null @@ -1,282 +0,0 @@ -[ - { - "description": "single dependency", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "dependencies": {"bar": ["foo"]} - }, - "tests": [ - { - "description": "neither", - "data": {}, - "valid": true - }, - { - "description": "nondependant", - "data": {"foo": 1}, - "valid": true - }, - { - "description": "with dependency", - "data": {"foo": 1, "bar": 2}, - "valid": true - }, - { - "description": "missing dependency", - "data": {"bar": 2}, - "valid": false - }, - { - "description": "ignores arrays", - "data": ["bar"], - "valid": true - }, - { - "description": "ignores strings", - "data": "foobar", - "valid": true - }, - { - "description": "ignores other non-objects", - "data": 12, - "valid": true - } - ] - }, - { - "description": "empty dependents", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "dependencies": {"bar": []} - }, - "tests": [ - { - "description": "empty object", - "data": {}, - "valid": true - }, - { - "description": "object with one property", - "data": {"bar": 2}, - "valid": true - }, - { - "description": "non-object is valid", - "data": 1, - "valid": true - } - ] - }, - { - "description": "multiple dependents required", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "dependencies": {"quux": ["foo", "bar"]} - }, - "tests": [ - { - "description": "neither", - "data": {}, - "valid": true - }, - { - "description": "nondependants", - "data": {"foo": 1, "bar": 2}, - "valid": true - }, - { - "description": "with dependencies", - "data": {"foo": 1, "bar": 2, "quux": 3}, - "valid": true - }, - { - "description": "missing dependency", - "data": {"foo": 1, "quux": 2}, - "valid": false - }, - { - "description": "missing other dependency", - "data": {"bar": 1, "quux": 2}, - "valid": false - }, - { - "description": "missing both dependencies", - "data": {"quux": 1}, - "valid": false - } - ] - }, - { - "description": "dependencies with escaped characters", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "dependencies": { - "foo\nbar": ["foo\rbar"], - "foo\"bar": ["foo'bar"] - } - }, - "tests": [ - { - "description": "CRLF", - "data": { - "foo\nbar": 1, - "foo\rbar": 2 - }, - "valid": true - }, - { - "description": "quoted quotes", - "data": { - "foo'bar": 1, - "foo\"bar": 2 - }, - "valid": true - }, - { - "description": "CRLF missing dependent", - "data": { - "foo\nbar": 1, - "foo": 2 - }, - "valid": false - }, - { - "description": "quoted quotes missing dependent", - "data": { - "foo\"bar": 2 - }, - "valid": false - } - ] - }, - { - "description": "single schema dependency", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "dependencies": { - "bar": { - "properties": { - "foo": {"type": "integer"}, - "bar": {"type": "integer"} - } - } - } - }, - "tests": [ - { - "description": "valid", - "data": {"foo": 1, "bar": 2}, - "valid": true - }, - { - "description": "no dependency", - "data": {"foo": "quux"}, - "valid": true - }, - { - "description": "wrong type", - "data": {"foo": "quux", "bar": 2}, - "valid": false - }, - { - "description": "wrong type other", - "data": {"foo": 2, "bar": "quux"}, - "valid": false - }, - { - "description": "wrong type both", - "data": {"foo": "quux", "bar": "quux"}, - "valid": false - }, - { - "description": "ignores arrays", - "data": ["bar"], - "valid": true - }, - { - "description": "ignores strings", - "data": "foobar", - "valid": true - }, - { - "description": "ignores other non-objects", - "data": 12, - "valid": true - } - ] - }, - { - "description": "boolean subschemas", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "dependencies": { - "foo": true, - "bar": false - } - }, - "tests": [ - { - "description": "object with property having schema true is valid", - "data": {"foo": 1}, - "valid": true - }, - { - "description": "object with property having schema false is invalid", - "data": {"bar": 2}, - "valid": false - }, - { - "description": "object with both properties is invalid", - "data": {"foo": 1, "bar": 2}, - "valid": false - }, - { - "description": "empty object is valid", - "data": {}, - "valid": true - } - ] - }, - { - "description": "schema dependencies with escaped characters", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "dependencies": { - "foo\tbar": {"minProperties": 4}, - "foo'bar": {"required": ["foo\"bar"]} - } - }, - "tests": [ - { - "description": "quoted tab", - "data": { - "foo\tbar": 1, - "a": 2, - "b": 3, - "c": 4 - }, - "valid": true - }, - { - "description": "quoted quote", - "data": { - "foo'bar": {"foo\"bar": 1} - }, - "valid": false - }, - { - "description": "quoted tab invalid under dependent schema", - "data": { - "foo\tbar": 1, - "a": 2 - }, - "valid": false - }, - { - "description": "quoted quote invalid under dependent schema", - "data": {"foo'bar": 1}, - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/dynamicRef.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/dynamicRef.json deleted file mode 100644 index 7e63f209..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/dynamicRef.json +++ /dev/null @@ -1,56 +0,0 @@ -[ - { - "description": "$dynamicRef skips over intermediate resources - pointer reference across resource boundary", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://test.json-schema.org/dynamic-ref-skips-intermediate-resource/optional/main", - "type": "object", - "properties": { - "bar-item": { - "$ref": "bar#/$defs/item" - } - }, - "$defs": { - "bar": { - "$id": "bar", - "type": "array", - "items": { - "$ref": "item" - }, - "$defs": { - "item": { - "$id": "item", - "type": "object", - "properties": { - "content": { - "$dynamicRef": "#content" - } - }, - "$defs": { - "defaultContent": { - "$dynamicAnchor": "content", - "type": "integer" - } - } - }, - "content": { - "$dynamicAnchor": "content", - "type": "string" - } - } - } - } - }, - "tests": [ - { - "description": "integer property passes", - "data": { "bar-item": { "content": 42 } }, - "valid": true - }, - { - "description": "string property fails", - "data": { "bar-item": { "content": "value" } }, - "valid": false - } - ] - }] \ No newline at end of file diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/ecmascript-regex.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/ecmascript-regex.json deleted file mode 100644 index a4d62e0c..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/ecmascript-regex.json +++ /dev/null @@ -1,582 +0,0 @@ -[ - { - "description": "ECMA 262 regex $ does not match trailing newline", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "string", - "pattern": "^abc$" - }, - "tests": [ - { - "description": "matches in Python, but not in ECMA 262", - "data": "abc\\n", - "valid": false - }, - { - "description": "matches", - "data": "abc", - "valid": true - } - ] - }, - { - "description": "ECMA 262 regex converts \\t to horizontal tab", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "string", - "pattern": "^\\t$" - }, - "tests": [ - { - "description": "does not match", - "data": "\\t", - "valid": false - }, - { - "description": "matches", - "data": "\u0009", - "valid": true - } - ] - }, - { - "description": "ECMA 262 regex escapes control codes with \\c and upper letter", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "string", - "pattern": "^\\cC$" - }, - "tests": [ - { - "description": "does not match", - "data": "\\cC", - "valid": false - }, - { - "description": "matches", - "data": "\u0003", - "valid": true - } - ] - }, - { - "description": "ECMA 262 regex escapes control codes with \\c and lower letter", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "string", - "pattern": "^\\cc$" - }, - "tests": [ - { - "description": "does not match", - "data": "\\cc", - "valid": false - }, - { - "description": "matches", - "data": "\u0003", - "valid": true - } - ] - }, - { - "description": "ECMA 262 \\d matches ascii digits only", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "string", - "pattern": "^\\d$" - }, - "tests": [ - { - "description": "ASCII zero matches", - "data": "0", - "valid": true - }, - { - "description": "NKO DIGIT ZERO does not match (unlike e.g. Python)", - "data": "߀", - "valid": false - }, - { - "description": "NKO DIGIT ZERO (as \\u escape) does not match", - "data": "\u07c0", - "valid": false - } - ] - }, - { - "description": "ECMA 262 \\D matches everything but ascii digits", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "string", - "pattern": "^\\D$" - }, - "tests": [ - { - "description": "ASCII zero does not match", - "data": "0", - "valid": false - }, - { - "description": "NKO DIGIT ZERO matches (unlike e.g. Python)", - "data": "߀", - "valid": true - }, - { - "description": "NKO DIGIT ZERO (as \\u escape) matches", - "data": "\u07c0", - "valid": true - } - ] - }, - { - "description": "ECMA 262 \\w matches ascii letters only", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "string", - "pattern": "^\\w$" - }, - "tests": [ - { - "description": "ASCII 'a' matches", - "data": "a", - "valid": true - }, - { - "description": "latin-1 e-acute does not match (unlike e.g. Python)", - "data": "é", - "valid": false - } - ] - }, - { - "description": "ECMA 262 \\W matches everything but ascii letters", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "string", - "pattern": "^\\W$" - }, - "tests": [ - { - "description": "ASCII 'a' does not match", - "data": "a", - "valid": false - }, - { - "description": "latin-1 e-acute matches (unlike e.g. Python)", - "data": "é", - "valid": true - } - ] - }, - { - "description": "ECMA 262 \\s matches whitespace", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "string", - "pattern": "^\\s$" - }, - "tests": [ - { - "description": "ASCII space matches", - "data": " ", - "valid": true - }, - { - "description": "Character tabulation matches", - "data": "\t", - "valid": true - }, - { - "description": "Line tabulation matches", - "data": "\u000b", - "valid": true - }, - { - "description": "Form feed matches", - "data": "\u000c", - "valid": true - }, - { - "description": "latin-1 non-breaking-space matches", - "data": "\u00a0", - "valid": true - }, - { - "description": "zero-width whitespace matches", - "data": "\ufeff", - "valid": true - }, - { - "description": "line feed matches (line terminator)", - "data": "\u000a", - "valid": true - }, - { - "description": "paragraph separator matches (line terminator)", - "data": "\u2029", - "valid": true - }, - { - "description": "EM SPACE matches (Space_Separator)", - "data": "\u2003", - "valid": true - }, - { - "description": "Non-whitespace control does not match", - "data": "\u0001", - "valid": false - }, - { - "description": "Non-whitespace does not match", - "data": "\u2013", - "valid": false - } - ] - }, - { - "description": "ECMA 262 \\S matches everything but whitespace", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "string", - "pattern": "^\\S$" - }, - "tests": [ - { - "description": "ASCII space does not match", - "data": " ", - "valid": false - }, - { - "description": "Character tabulation does not match", - "data": "\t", - "valid": false - }, - { - "description": "Line tabulation does not match", - "data": "\u000b", - "valid": false - }, - { - "description": "Form feed does not match", - "data": "\u000c", - "valid": false - }, - { - "description": "latin-1 non-breaking-space does not match", - "data": "\u00a0", - "valid": false - }, - { - "description": "zero-width whitespace does not match", - "data": "\ufeff", - "valid": false - }, - { - "description": "line feed does not match (line terminator)", - "data": "\u000a", - "valid": false - }, - { - "description": "paragraph separator does not match (line terminator)", - "data": "\u2029", - "valid": false - }, - { - "description": "EM SPACE does not match (Space_Separator)", - "data": "\u2003", - "valid": false - }, - { - "description": "Non-whitespace control matches", - "data": "\u0001", - "valid": true - }, - { - "description": "Non-whitespace matches", - "data": "\u2013", - "valid": true - } - ] - }, - { - "description": "patterns always use unicode semantics with pattern", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "pattern": "\\p{Letter}cole" - }, - "tests": [ - { - "description": "ascii character in json string", - "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.", - "valid": true - }, - { - "description": "literal unicode character in json string", - "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.", - "valid": true - }, - { - "description": "unicode character in hex format in string", - "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.", - "valid": true - }, - { - "description": "unicode matching is case-sensitive", - "data": "LES HIVERS DE MON ENFANCE ÉTAIENT DES SAISONS LONGUES, LONGUES. NOUS VIVIONS EN TROIS LIEUX: L'ÉCOLE, L'ÉGLISE ET LA PATINOIRE; MAIS LA VRAIE VIE ÉTAIT SUR LA PATINOIRE.", - "valid": false - } - ] - }, - { - "description": "\\w in patterns matches [A-Za-z0-9_], not unicode letters", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "pattern": "\\wcole" - }, - "tests": [ - { - "description": "ascii character in json string", - "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.", - "valid": true - }, - { - "description": "literal unicode character in json string", - "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.", - "valid": false - }, - { - "description": "unicode character in hex format in string", - "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.", - "valid": false - }, - { - "description": "unicode matching is case-sensitive", - "data": "LES HIVERS DE MON ENFANCE ÉTAIENT DES SAISONS LONGUES, LONGUES. NOUS VIVIONS EN TROIS LIEUX: L'ÉCOLE, L'ÉGLISE ET LA PATINOIRE; MAIS LA VRAIE VIE ÉTAIT SUR LA PATINOIRE.", - "valid": false - } - ] - }, - { - "description": "pattern with ASCII ranges", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "pattern": "[a-z]cole" - }, - "tests": [ - { - "description": "literal unicode character in json string", - "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'école, l'église et la patinoire; mais la vraie vie était sur la patinoire.", - "valid": false - }, - { - "description": "unicode character in hex format in string", - "data": "Les hivers de mon enfance étaient des saisons longues, longues. Nous vivions en trois lieux: l'\u00e9cole, l'église et la patinoire; mais la vraie vie était sur la patinoire.", - "valid": false - }, - { - "description": "ascii characters match", - "data": "Les hivers de mon enfance etaient des saisons longues, longues. Nous vivions en trois lieux: l'ecole, l'eglise et la patinoire; mais la vraie vie etait sur la patinoire.", - "valid": true - } - ] - }, - { - "description": "\\d in pattern matches [0-9], not unicode digits", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "pattern": "^\\d+$" - }, - "tests": [ - { - "description": "ascii digits", - "data": "42", - "valid": true - }, - { - "description": "ascii non-digits", - "data": "-%#", - "valid": false - }, - { - "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", - "data": "৪২", - "valid": false - } - ] - }, - { - "description": "pattern with non-ASCII digits", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "pattern": "^\\p{digit}+$" - }, - "tests": [ - { - "description": "ascii digits", - "data": "42", - "valid": true - }, - { - "description": "ascii non-digits", - "data": "-%#", - "valid": false - }, - { - "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", - "data": "৪২", - "valid": true - } - ] - }, - { - "description": "patterns always use unicode semantics with patternProperties", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "patternProperties": { - "\\p{Letter}cole": true - }, - "additionalProperties": false - }, - "tests": [ - { - "description": "ascii character in json string", - "data": { "l'ecole": "pas de vraie vie" }, - "valid": true - }, - { - "description": "literal unicode character in json string", - "data": { "l'école": "pas de vraie vie" }, - "valid": true - }, - { - "description": "unicode character in hex format in string", - "data": { "l'\u00e9cole": "pas de vraie vie" }, - "valid": true - }, - { - "description": "unicode matching is case-sensitive", - "data": { "L'ÉCOLE": "PAS DE VRAIE VIE" }, - "valid": false - } - ] - }, - { - "description": "\\w in patternProperties matches [A-Za-z0-9_], not unicode letters", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "patternProperties": { - "\\wcole": true - }, - "additionalProperties": false - }, - "tests": [ - { - "description": "ascii character in json string", - "data": { "l'ecole": "pas de vraie vie" }, - "valid": true - }, - { - "description": "literal unicode character in json string", - "data": { "l'école": "pas de vraie vie" }, - "valid": false - }, - { - "description": "unicode character in hex format in string", - "data": { "l'\u00e9cole": "pas de vraie vie" }, - "valid": false - }, - { - "description": "unicode matching is case-sensitive", - "data": { "L'ÉCOLE": "PAS DE VRAIE VIE" }, - "valid": false - } - ] - }, - { - "description": "patternProperties with ASCII ranges", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "patternProperties": { - "[a-z]cole": true - }, - "additionalProperties": false - }, - "tests": [ - { - "description": "literal unicode character in json string", - "data": { "l'école": "pas de vraie vie" }, - "valid": false - }, - { - "description": "unicode character in hex format in string", - "data": { "l'\u00e9cole": "pas de vraie vie" }, - "valid": false - }, - { - "description": "ascii characters match", - "data": { "l'ecole": "pas de vraie vie" }, - "valid": true - } - ] - }, - { - "description": "\\d in patternProperties matches [0-9], not unicode digits", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "patternProperties": { - "^\\d+$": true - }, - "additionalProperties": false - }, - "tests": [ - { - "description": "ascii digits", - "data": { "42": "life, the universe, and everything" }, - "valid": true - }, - { - "description": "ascii non-digits", - "data": { "-%#": "spending the year dead for tax reasons" }, - "valid": false - }, - { - "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", - "data": { "৪২": "khajit has wares if you have coin" }, - "valid": false - } - ] - }, - { - "description": "patternProperties with non-ASCII digits", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object", - "patternProperties": { - "^\\p{digit}+$": true - }, - "additionalProperties": false - }, - "tests": [ - { - "description": "ascii digits", - "data": { "42": "life, the universe, and everything" }, - "valid": true - }, - { - "description": "ascii non-digits", - "data": { "-%#": "spending the year dead for tax reasons" }, - "valid": false - }, - { - "description": "non-ascii digits (BENGALI DIGIT FOUR, BENGALI DIGIT TWO)", - "data": { "৪২": "khajit has wares if you have coin" }, - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/float-overflow.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/float-overflow.json deleted file mode 100644 index f5ae8b18..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/float-overflow.json +++ /dev/null @@ -1,17 +0,0 @@ -[ - { - "description": "all integers are multiples of 0.5, if overflow is handled", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "integer", - "multipleOf": 0.5 - }, - "tests": [ - { - "description": "valid if optional overflow handling is implemented", - "data": 1e308, - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format-assertion.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format-assertion.json deleted file mode 100644 index 03400370..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format-assertion.json +++ /dev/null @@ -1,42 +0,0 @@ -[ - { - "description": "schema that uses custom metaschema with format-assertion: false", - "schema": { - "$id": "https://schema/using/format-assertion/false", - "$schema": "http://localhost:1234/draft2020-12/format-assertion-false.json", - "format": "ipv4" - }, - "tests": [ - { - "description": "format-assertion: false: valid string", - "data": "127.0.0.1", - "valid": true - }, - { - "description": "format-assertion: false: invalid string", - "data": "not-an-ipv4", - "valid": false - } - ] - }, - { - "description": "schema that uses custom metaschema with format-assertion: true", - "schema": { - "$id": "https://schema/using/format-assertion/true", - "$schema": "http://localhost:1234/draft2020-12/format-assertion-true.json", - "format": "ipv4" - }, - "tests": [ - { - "description": "format-assertion: true: valid string", - "data": "127.0.0.1", - "valid": true - }, - { - "description": "format-assertion: true: invalid string", - "data": "not-an-ipv4", - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/date-time.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/date-time.json deleted file mode 100644 index c764a173..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/date-time.json +++ /dev/null @@ -1,141 +0,0 @@ -[ - { - "description": "validation of date-time strings", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "date-time" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "a valid date-time string", - "data": "1963-06-19T08:30:06.283185Z", - "valid": true - }, - { - "description": "a valid date-time string without second fraction", - "data": "1963-06-19T08:30:06Z", - "valid": true - }, - { - "description": "a valid date-time string with plus offset", - "data": "1937-01-01T12:00:27.87+00:20", - "valid": true - }, - { - "description": "a valid date-time string with minus offset", - "data": "1990-12-31T15:59:50.123-08:00", - "valid": true - }, - { - "description": "a valid date-time with a leap second, UTC", - "data": "1998-12-31T23:59:60Z", - "valid": true - }, - { - "description": "a valid date-time with a leap second, with minus offset", - "data": "1998-12-31T15:59:60.123-08:00", - "valid": true - }, - { - "description": "an invalid date-time past leap second, UTC", - "data": "1998-12-31T23:59:61Z", - "valid": false - }, - { - "description": "an invalid date-time with leap second on a wrong minute, UTC", - "data": "1998-12-31T23:58:60Z", - "valid": false - }, - { - "description": "an invalid date-time with leap second on a wrong hour, UTC", - "data": "1998-12-31T22:59:60Z", - "valid": false - }, - { - "description": "an invalid day in date-time string", - "data": "1990-02-31T15:59:59.123-08:00", - "valid": false - }, - { - "description": "an invalid offset in date-time string", - "data": "1990-12-31T15:59:59-24:00", - "valid": false - }, - { - "description": "an invalid closing Z after time-zone offset", - "data": "1963-06-19T08:30:06.28123+01:00Z", - "valid": false - }, - { - "description": "an invalid date-time string", - "data": "06/19/1963 08:30:06 PST", - "valid": false - }, - { - "description": "case-insensitive T and Z", - "data": "1963-06-19t08:30:06.283185z", - "valid": true - }, - { - "description": "only RFC3339 not all of ISO 8601 are valid", - "data": "2013-350T01:01:01", - "valid": false - }, - { - "description": "invalid non-padded month dates", - "data": "1963-6-19T08:30:06.283185Z", - "valid": false - }, - { - "description": "invalid non-padded day dates", - "data": "1963-06-1T08:30:06.283185Z", - "valid": false - }, - { - "description": "invalid non-ASCII '৪' (a Bengali 4) in date portion", - "data": "1963-06-1৪T00:00:00Z", - "valid": false - }, - { - "description": "invalid non-ASCII '৪' (a Bengali 4) in time portion", - "data": "1963-06-11T0৪:00:00Z", - "valid": false - }, - { - "description": "invalid extended year", - "data": "+11963-06-19T08:30:06.283185Z", - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/date.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/date.json deleted file mode 100644 index 01731c34..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/date.json +++ /dev/null @@ -1,251 +0,0 @@ -[ - { - "description": "validation of date strings", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "date" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "a valid date string", - "data": "1963-06-19", - "valid": true - }, - { - "description": "a valid date string with 31 days in January", - "data": "2020-01-31", - "valid": true - }, - { - "description": "a invalid date string with 32 days in January", - "data": "2020-01-32", - "valid": false - }, - { - "description": "a valid date string with 28 days in February (normal)", - "data": "2021-02-28", - "valid": true - }, - { - "description": "a invalid date string with 29 days in February (normal)", - "data": "2021-02-29", - "valid": false - }, - { - "description": "a valid date string with 29 days in February (leap)", - "data": "2020-02-29", - "valid": true - }, - { - "description": "a invalid date string with 30 days in February (leap)", - "data": "2020-02-30", - "valid": false - }, - { - "description": "a valid date string with 31 days in March", - "data": "2020-03-31", - "valid": true - }, - { - "description": "a invalid date string with 32 days in March", - "data": "2020-03-32", - "valid": false - }, - { - "description": "a valid date string with 30 days in April", - "data": "2020-04-30", - "valid": true - }, - { - "description": "a invalid date string with 31 days in April", - "data": "2020-04-31", - "valid": false - }, - { - "description": "a valid date string with 31 days in May", - "data": "2020-05-31", - "valid": true - }, - { - "description": "a invalid date string with 32 days in May", - "data": "2020-05-32", - "valid": false - }, - { - "description": "a valid date string with 30 days in June", - "data": "2020-06-30", - "valid": true - }, - { - "description": "a invalid date string with 31 days in June", - "data": "2020-06-31", - "valid": false - }, - { - "description": "a valid date string with 31 days in July", - "data": "2020-07-31", - "valid": true - }, - { - "description": "a invalid date string with 32 days in July", - "data": "2020-07-32", - "valid": false - }, - { - "description": "a valid date string with 31 days in August", - "data": "2020-08-31", - "valid": true - }, - { - "description": "a invalid date string with 32 days in August", - "data": "2020-08-32", - "valid": false - }, - { - "description": "a valid date string with 30 days in September", - "data": "2020-09-30", - "valid": true - }, - { - "description": "a invalid date string with 31 days in September", - "data": "2020-09-31", - "valid": false - }, - { - "description": "a valid date string with 31 days in October", - "data": "2020-10-31", - "valid": true - }, - { - "description": "a invalid date string with 32 days in October", - "data": "2020-10-32", - "valid": false - }, - { - "description": "a valid date string with 30 days in November", - "data": "2020-11-30", - "valid": true - }, - { - "description": "a invalid date string with 31 days in November", - "data": "2020-11-31", - "valid": false - }, - { - "description": "a valid date string with 31 days in December", - "data": "2020-12-31", - "valid": true - }, - { - "description": "a invalid date string with 32 days in December", - "data": "2020-12-32", - "valid": false - }, - { - "description": "a invalid date string with invalid month", - "data": "2020-13-01", - "valid": false - }, - { - "description": "an invalid date string", - "data": "06/19/1963", - "valid": false - }, - { - "description": "only RFC3339 not all of ISO 8601 are valid", - "data": "2013-350", - "valid": false - }, - { - "description": "non-padded month dates are not valid", - "data": "1998-1-20", - "valid": false - }, - { - "description": "non-padded day dates are not valid", - "data": "1998-01-1", - "valid": false - }, - { - "description": "invalid month", - "data": "1998-13-01", - "valid": false - }, - { - "description": "invalid month-day combination", - "data": "1998-04-31", - "valid": false - }, - { - "description": "2021 is not a leap year", - "data": "2021-02-29", - "valid": false - }, - { - "description": "2020 is a leap year", - "data": "2020-02-29", - "valid": true - }, - { - "description": "invalid non-ASCII '৪' (a Bengali 4)", - "data": "1963-06-1৪", - "valid": false - }, - { - "description": "ISO8601 / non-RFC3339: YYYYMMDD without dashes (2023-03-28)", - "data": "20230328", - "valid": false - }, - { - "description": "ISO8601 / non-RFC3339: week number implicit day of week (2023-01-02)", - "data": "2023-W01", - "valid": false - }, - { - "description": "ISO8601 / non-RFC3339: week number with day of week (2023-03-28)", - "data": "2023-W13-2", - "valid": false - }, - { - "description": "ISO8601 / non-RFC3339: week number rollover to next year (2023-01-01)", - "data": "2022W527", - "valid": false - }, - { - "description": "an invalid time string in date-time format", - "data": "2020-11-28T23:55:45Z", - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/duration.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/duration.json deleted file mode 100644 index a09fec5e..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/duration.json +++ /dev/null @@ -1,141 +0,0 @@ -[ - { - "description": "validation of duration strings", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "duration" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "a valid duration string", - "data": "P4DT12H30M5S", - "valid": true - }, - { - "description": "an invalid duration string", - "data": "PT1D", - "valid": false - }, - { - "description": "must start with P", - "data": "4DT12H30M5S", - "valid": false - }, - { - "description": "no elements present", - "data": "P", - "valid": false - }, - { - "description": "no time elements present", - "data": "P1YT", - "valid": false - }, - { - "description": "no date or time elements present", - "data": "PT", - "valid": false - }, - { - "description": "elements out of order", - "data": "P2D1Y", - "valid": false - }, - { - "description": "missing time separator", - "data": "P1D2H", - "valid": false - }, - { - "description": "time element in the date position", - "data": "P2S", - "valid": false - }, - { - "description": "four years duration", - "data": "P4Y", - "valid": true - }, - { - "description": "zero time, in seconds", - "data": "PT0S", - "valid": true - }, - { - "description": "zero time, in days", - "data": "P0D", - "valid": true - }, - { - "description": "one month duration", - "data": "P1M", - "valid": true - }, - { - "description": "one minute duration", - "data": "PT1M", - "valid": true - }, - { - "description": "one and a half days, in hours", - "data": "PT36H", - "valid": true - }, - { - "description": "one and a half days, in days and hours", - "data": "P1DT12H", - "valid": true - }, - { - "description": "two weeks", - "data": "P2W", - "valid": true - }, - { - "description": "weeks cannot be combined with other units", - "data": "P1Y2W", - "valid": false - }, - { - "description": "invalid non-ASCII '২' (a Bengali 2)", - "data": "P২Y", - "valid": false - }, - { - "description": "element without unit", - "data": "P1", - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/ecmascript-regex.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/ecmascript-regex.json deleted file mode 100644 index b0648084..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/ecmascript-regex.json +++ /dev/null @@ -1,16 +0,0 @@ -[ - { - "description": "\\a is not an ECMA 262 control escape", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "regex" - }, - "tests": [ - { - "description": "when used as a pattern", - "data": "\\a", - "valid": false - } - ] - } -] \ No newline at end of file diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/email.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/email.json deleted file mode 100644 index 925c2f2e..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/email.json +++ /dev/null @@ -1,131 +0,0 @@ -[ - { - "description": "validation of e-mail addresses", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "email" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "a valid e-mail address", - "data": "joe.bloggs@example.com", - "valid": true - }, - { - "description": "an invalid e-mail address", - "data": "2962", - "valid": false - }, - { - "description": "tilde in local part is valid", - "data": "te~st@example.com", - "valid": true - }, - { - "description": "tilde before local part is valid", - "data": "~test@example.com", - "valid": true - }, - { - "description": "tilde after local part is valid", - "data": "test~@example.com", - "valid": true - }, - { - "description": "a quoted string with a space in the local part is valid", - "data": "\"joe bloggs\"@example.com", - "valid": true - }, - { - "description": "a quoted string with a double dot in the local part is valid", - "data": "\"joe..bloggs\"@example.com", - "valid": true - }, - { - "description": "a quoted string with a @ in the local part is valid", - "data": "\"joe@bloggs\"@example.com", - "valid": true - }, - { - "description": "an IPv4-address-literal after the @ is valid", - "data": "joe.bloggs@[127.0.0.1]", - "valid": true - }, - { - "description": "an IPv6-address-literal after the @ is valid", - "data": "joe.bloggs@[IPv6:::1]", - "valid": true - }, - { - "description": "dot before local part is not valid", - "data": ".test@example.com", - "valid": false - }, - { - "description": "dot after local part is not valid", - "data": "test.@example.com", - "valid": false - }, - { - "description": "two separated dots inside local part are valid", - "data": "te.s.t@example.com", - "valid": true - }, - { - "description": "two subsequent dots inside local part are not valid", - "data": "te..st@example.com", - "valid": false - }, - { - "description": "an invalid domain", - "data": "joe.bloggs@invalid=domain.com", - "valid": false - }, - { - "description": "an invalid IPv4-address-literal", - "data": "joe.bloggs@[127.0.0.300]", - "valid": false - }, - { - "description": "two email addresses is not valid", - "data": "user1@oceania.org, user2@oceania.org", - "valid": false - }, - { - "description": "full \"From\" header is invalid", - "data": "\"Winston Smith\" (Records Department)", - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/hostname.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/hostname.json deleted file mode 100644 index 511995ae..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/hostname.json +++ /dev/null @@ -1,361 +0,0 @@ -[ - { - "description": "validation of host names", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "hostname" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "a valid host name", - "data": "www.example.com", - "valid": true - }, - { - "description": "single label", - "data": "hostname", - "valid": true - }, - { - "description": "single label with digits", - "data": "h0stn4me", - "valid": true - }, - { - "description": "single label starting with digit", - "data": "1host", - "valid": true - }, - { - "description": "single label ending with digit", - "data": "hostnam3", - "valid": true - }, - { - "description": "empty string", - "data": "", - "valid": false - }, - { - "description": "single dot", - "data": ".", - "valid": false - }, - { - "description": "leading dot", - "data": ".example", - "valid": false - }, - { - "description": "trailing dot", - "data": "example.", - "valid": false - }, - { - "description": "IDN label separator", - "data": "example\uff0ecom", - "valid": false - }, - { - "description": "single label with hyphen", - "data": "host-name", - "valid": true - }, - { - "description": "starts with hyphen", - "data": "-hostname", - "valid": false - }, - { - "description": "ends with hyphen", - "data": "hostname-", - "valid": false - }, - { - "description": "contains \"--\" in the 3rd and 4th position", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1 https://tools.ietf.org/html/rfc5890#section-2.3.2.1", - "data": "XN--aa---o47jg78q", - "valid": false - }, - { - "description": "contains underscore", - "data": "host_name", - "valid": false - }, - { - "description": "exceeds maximum overall length (256)", - "data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.com", - "valid": false - }, - { - "description": "maximum label length (63)", - "data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijk.com", - "valid": true - }, - { - "description": "exceeds maximum label length (63)", - "data": "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl.com", - "valid": false - } - ] - }, - { - "description": "validation of A-label (punycode) host names", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "hostname" - }, - "tests": [ - { - "description": "invalid Punycode", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.4 https://tools.ietf.org/html/rfc5890#section-2.3.2.1", - "data": "xn--X", - "valid": false - }, - { - "description": "a valid host name (example.test in Hangul)", - "data": "xn--9n2bp8q.xn--9t4b11yi5a", - "valid": true - }, - { - "description": "contains illegal char U+302E Hangul single dot tone mark", - "data": "xn--07jt112bpxg.xn--9t4b11yi5a", - "valid": false - }, - { - "description": "Begins with a Spacing Combining Mark", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2", - "data": "xn--hello-txk", - "valid": false - }, - { - "description": "Begins with a Nonspacing Mark", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2", - "data": "xn--hello-zed", - "valid": false - }, - { - "description": "Begins with an Enclosing Mark", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2", - "data": "xn--hello-6bf", - "valid": false - }, - { - "description": "Exceptions that are PVALID, left-to-right chars", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6", - "data": "xn--zca29lwxobi7a", - "valid": true - }, - { - "description": "Exceptions that are PVALID, right-to-left chars", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6", - "data": "xn--qmbc", - "valid": true - }, - { - "description": "Exceptions that are DISALLOWED, right-to-left chars", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6", - "data": "xn--chb89f", - "valid": false - }, - { - "description": "Exceptions that are DISALLOWED, left-to-right chars", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6 Note: The two combining marks (U+302E and U+302F) are in the middle and not at the start", - "data": "xn--07jceefgh4c", - "valid": false - }, - { - "description": "MIDDLE DOT with no preceding 'l'", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", - "data": "xn--al-0ea", - "valid": false - }, - { - "description": "MIDDLE DOT with nothing preceding", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", - "data": "xn--l-fda", - "valid": false - }, - { - "description": "MIDDLE DOT with no following 'l'", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", - "data": "xn--la-0ea", - "valid": false - }, - { - "description": "MIDDLE DOT with nothing following", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", - "data": "xn--l-gda", - "valid": false - }, - { - "description": "MIDDLE DOT with surrounding 'l's", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", - "data": "xn--ll-0ea", - "valid": true - }, - { - "description": "Greek KERAIA not followed by Greek", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4", - "data": "xn--S-jib3p", - "valid": false - }, - { - "description": "Greek KERAIA not followed by anything", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4", - "data": "xn--wva3j", - "valid": false - }, - { - "description": "Greek KERAIA followed by Greek", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4", - "data": "xn--wva3je", - "valid": true - }, - { - "description": "Hebrew GERESH not preceded by Hebrew", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5", - "data": "xn--A-2hc5h", - "valid": false - }, - { - "description": "Hebrew GERESH not preceded by anything", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5", - "data": "xn--5db1e", - "valid": false - }, - { - "description": "Hebrew GERESH preceded by Hebrew", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5", - "data": "xn--4dbc5h", - "valid": true - }, - { - "description": "Hebrew GERSHAYIM not preceded by Hebrew", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6", - "data": "xn--A-2hc8h", - "valid": false - }, - { - "description": "Hebrew GERSHAYIM not preceded by anything", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6", - "data": "xn--5db3e", - "valid": false - }, - { - "description": "Hebrew GERSHAYIM preceded by Hebrew", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6", - "data": "xn--4dbc8h", - "valid": true - }, - { - "description": "KATAKANA MIDDLE DOT with no Hiragana, Katakana, or Han", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", - "data": "xn--defabc-k64e", - "valid": false - }, - { - "description": "KATAKANA MIDDLE DOT with no other characters", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", - "data": "xn--vek", - "valid": false - }, - { - "description": "KATAKANA MIDDLE DOT with Hiragana", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", - "data": "xn--k8j5u", - "valid": true - }, - { - "description": "KATAKANA MIDDLE DOT with Katakana", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", - "data": "xn--bck0j", - "valid": true - }, - { - "description": "KATAKANA MIDDLE DOT with Han", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", - "data": "xn--vek778f", - "valid": true - }, - { - "description": "Arabic-Indic digits mixed with Extended Arabic-Indic digits", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.8", - "data": "xn--ngb6iyr", - "valid": false - }, - { - "description": "Arabic-Indic digits not mixed with Extended Arabic-Indic digits", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.8", - "data": "xn--ngba1o", - "valid": true - }, - { - "description": "Extended Arabic-Indic digits not mixed with Arabic-Indic digits", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.9", - "data": "xn--0-gyc", - "valid": true - }, - { - "description": "ZERO WIDTH JOINER not preceded by Virama", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf", - "data": "xn--11b2er09f", - "valid": false - }, - { - "description": "ZERO WIDTH JOINER not preceded by anything", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf", - "data": "xn--02b508i", - "valid": false - }, - { - "description": "ZERO WIDTH JOINER preceded by Virama", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf", - "data": "xn--11b2ezcw70k", - "valid": true - }, - { - "description": "ZERO WIDTH NON-JOINER preceded by Virama", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.1", - "data": "xn--11b2ezcs70k", - "valid": true - }, - { - "description": "ZERO WIDTH NON-JOINER not preceded by Virama but matches regexp", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.1 https://www.w3.org/TR/alreq/#h_disjoining_enforcement", - "data": "xn--ngba5hb2804a", - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/idn-email.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/idn-email.json deleted file mode 100644 index 50f3c23c..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/idn-email.json +++ /dev/null @@ -1,61 +0,0 @@ -[ - { - "description": "validation of an internationalized e-mail addresses", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "idn-email" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "a valid idn e-mail (example@example.test in Hangul)", - "data": "실례@실례.테스트", - "valid": true - }, - { - "description": "an invalid idn e-mail address", - "data": "2962", - "valid": false - }, - { - "description": "a valid e-mail address", - "data": "joe.bloggs@example.com", - "valid": true - }, - { - "description": "an invalid e-mail address", - "data": "2962", - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/idn-hostname.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/idn-hostname.json deleted file mode 100644 index 3bb59820..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/idn-hostname.json +++ /dev/null @@ -1,449 +0,0 @@ -[ - { - "description": "validation of internationalized host names", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "idn-hostname" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "a valid host name (example.test in Hangul)", - "data": "실례.테스트", - "valid": true - }, - { - "description": "illegal first char U+302E Hangul single dot tone mark", - "data": "〮실례.테스트", - "valid": false - }, - { - "description": "contains illegal char U+302E Hangul single dot tone mark", - "data": "실〮례.테스트", - "valid": false - }, - { - "description": "a host name with a component too long", - "data": "실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실실례례테스트례례례례례례례례례례례례례례례례례테스트례례례례례례례례례례례례례례례례례례례테스트례례례례례례례례례례례례테스트례례실례.테스트", - "valid": false - }, - { - "description": "invalid label, correct Punycode", - "comment": "https://tools.ietf.org/html/rfc5890#section-2.3.2.1 https://tools.ietf.org/html/rfc5891#section-4.4 https://tools.ietf.org/html/rfc3492#section-7.1", - "data": "-> $1.00 <--", - "valid": false - }, - { - "description": "valid Chinese Punycode", - "comment": "https://tools.ietf.org/html/rfc5890#section-2.3.2.1 https://tools.ietf.org/html/rfc5891#section-4.4", - "data": "xn--ihqwcrb4cv8a8dqg056pqjye", - "valid": true - }, - { - "description": "invalid Punycode", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.4 https://tools.ietf.org/html/rfc5890#section-2.3.2.1", - "data": "xn--X", - "valid": false - }, - { - "description": "U-label contains \"--\" in the 3rd and 4th position", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1 https://tools.ietf.org/html/rfc5890#section-2.3.2.1", - "data": "XN--aa---o47jg78q", - "valid": false - }, - { - "description": "U-label starts with a dash", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1", - "data": "-hello", - "valid": false - }, - { - "description": "U-label ends with a dash", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1", - "data": "hello-", - "valid": false - }, - { - "description": "U-label starts and ends with a dash", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.1", - "data": "-hello-", - "valid": false - }, - { - "description": "Begins with a Spacing Combining Mark", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2", - "data": "\u0903hello", - "valid": false - }, - { - "description": "Begins with a Nonspacing Mark", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2", - "data": "\u0300hello", - "valid": false - }, - { - "description": "Begins with an Enclosing Mark", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.2", - "data": "\u0488hello", - "valid": false - }, - { - "description": "Exceptions that are PVALID, left-to-right chars", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6", - "data": "\u00df\u03c2\u0f0b\u3007", - "valid": true - }, - { - "description": "Exceptions that are PVALID, right-to-left chars", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6", - "data": "\u06fd\u06fe", - "valid": true - }, - { - "description": "Exceptions that are DISALLOWED, right-to-left chars", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6", - "data": "\u0640\u07fa", - "valid": false - }, - { - "description": "Exceptions that are DISALLOWED, left-to-right chars", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.2 https://tools.ietf.org/html/rfc5892#section-2.6 Note: The two combining marks (U+302E and U+302F) are in the middle and not at the start", - "data": "\u3031\u3032\u3033\u3034\u3035\u302e\u302f\u303b", - "valid": false - }, - { - "description": "MIDDLE DOT with no preceding 'l'", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", - "data": "a\u00b7l", - "valid": false - }, - { - "description": "MIDDLE DOT with nothing preceding", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", - "data": "\u00b7l", - "valid": false - }, - { - "description": "MIDDLE DOT with no following 'l'", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", - "data": "l\u00b7a", - "valid": false - }, - { - "description": "MIDDLE DOT with nothing following", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", - "data": "l\u00b7", - "valid": false - }, - { - "description": "MIDDLE DOT with surrounding 'l's", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.3", - "data": "l\u00b7l", - "valid": true - }, - { - "description": "Greek KERAIA not followed by Greek", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4", - "data": "\u03b1\u0375S", - "valid": false - }, - { - "description": "Greek KERAIA not followed by anything", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4", - "data": "\u03b1\u0375", - "valid": false - }, - { - "description": "Greek KERAIA followed by Greek", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.4", - "data": "\u03b1\u0375\u03b2", - "valid": true - }, - { - "description": "Hebrew GERESH not preceded by Hebrew", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5", - "data": "A\u05f3\u05d1", - "valid": false - }, - { - "description": "Hebrew GERESH not preceded by anything", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5", - "data": "\u05f3\u05d1", - "valid": false - }, - { - "description": "Hebrew GERESH preceded by Hebrew", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.5", - "data": "\u05d0\u05f3\u05d1", - "valid": true - }, - { - "description": "Hebrew GERSHAYIM not preceded by Hebrew", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6", - "data": "A\u05f4\u05d1", - "valid": false - }, - { - "description": "Hebrew GERSHAYIM not preceded by anything", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6", - "data": "\u05f4\u05d1", - "valid": false - }, - { - "description": "Hebrew GERSHAYIM preceded by Hebrew", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.6", - "data": "\u05d0\u05f4\u05d1", - "valid": true - }, - { - "description": "KATAKANA MIDDLE DOT with no Hiragana, Katakana, or Han", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", - "data": "def\u30fbabc", - "valid": false - }, - { - "description": "KATAKANA MIDDLE DOT with no other characters", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", - "data": "\u30fb", - "valid": false - }, - { - "description": "KATAKANA MIDDLE DOT with Hiragana", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", - "data": "\u30fb\u3041", - "valid": true - }, - { - "description": "KATAKANA MIDDLE DOT with Katakana", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", - "data": "\u30fb\u30a1", - "valid": true - }, - { - "description": "KATAKANA MIDDLE DOT with Han", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.7", - "data": "\u30fb\u4e08", - "valid": true - }, - { - "description": "Arabic-Indic digits mixed with Extended Arabic-Indic digits", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.8", - "data": "\u0628\u0660\u06f0", - "valid": false - }, - { - "description": "Arabic-Indic digits not mixed with Extended Arabic-Indic digits", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.8", - "data": "\u0628\u0660\u0628", - "valid": true - }, - { - "description": "Extended Arabic-Indic digits not mixed with Arabic-Indic digits", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.9", - "data": "\u06f00", - "valid": true - }, - { - "description": "ZERO WIDTH JOINER not preceded by Virama", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf", - "data": "\u0915\u200d\u0937", - "valid": false - }, - { - "description": "ZERO WIDTH JOINER not preceded by anything", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf", - "data": "\u200d\u0937", - "valid": false - }, - { - "description": "ZERO WIDTH JOINER preceded by Virama", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.2 https://www.unicode.org/review/pr-37.pdf", - "data": "\u0915\u094d\u200d\u0937", - "valid": true - }, - { - "description": "ZERO WIDTH NON-JOINER preceded by Virama", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.1", - "data": "\u0915\u094d\u200c\u0937", - "valid": true - }, - { - "description": "ZERO WIDTH NON-JOINER not preceded by Virama but matches regexp", - "comment": "https://tools.ietf.org/html/rfc5891#section-4.2.3.3 https://tools.ietf.org/html/rfc5892#appendix-A.1 https://www.w3.org/TR/alreq/#h_disjoining_enforcement", - "data": "\u0628\u064a\u200c\u0628\u064a", - "valid": true - }, - { - "description": "single label", - "data": "hostname", - "valid": true - }, - { - "description": "single label with hyphen", - "data": "host-name", - "valid": true - }, - { - "description": "single label with digits", - "data": "h0stn4me", - "valid": true - }, - { - "description": "single label starting with digit", - "data": "1host", - "valid": true - }, - { - "description": "single label ending with digit", - "data": "hostnam3", - "valid": true - }, - { - "description": "empty string", - "data": "", - "valid": false - } - ] - }, - { - "description": "validation of separators in internationalized host names", - "specification": [ - {"rfc3490": "3.1", "quote": "Whenever dots are used as label separators, the following characters MUST be recognized as dots: U+002E (full stop), U+3002 (ideographic full stop), U+FF0E (fullwidth full stop), U+FF61(halfwidth ideographic full stop)"} - ], - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "idn-hostname" - }, - "tests": [ - { - "description": "single dot", - "data": ".", - "valid": false - }, - { - "description": "single ideographic full stop", - "data": "\u3002", - "valid": false - }, - { - "description": "single fullwidth full stop", - "data": "\uff0e", - "valid": false - }, - { - "description": "single halfwidth ideographic full stop", - "data": "\uff61", - "valid": false - }, - { - "description": "dot as label separator", - "data": "a.b", - "valid": true - }, - { - "description": "ideographic full stop as label separator", - "data": "a\u3002b", - "valid": true - }, - { - "description": "fullwidth full stop as label separator", - "data": "a\uff0eb", - "valid": true - }, - { - "description": "halfwidth ideographic full stop as label separator", - "data": "a\uff61b", - "valid": true - }, - { - "description": "leading dot", - "data": ".example", - "valid": false - }, - { - "description": "leading ideographic full stop", - "data": "\u3002example", - "valid": false - }, - { - "description": "leading fullwidth full stop", - "data": "\uff0eexample", - "valid": false - }, - { - "description": "leading halfwidth ideographic full stop", - "data": "\uff61example", - "valid": false - }, - { - "description": "trailing dot", - "data": "example.", - "valid": false - }, - { - "description": "trailing ideographic full stop", - "data": "example\u3002", - "valid": false - }, - { - "description": "trailing fullwidth full stop", - "data": "example\uff0e", - "valid": false - }, - { - "description": "trailing halfwidth ideographic full stop", - "data": "example\uff61", - "valid": false - }, - { - "description": "label too long if separator ignored (full stop)", - "data": "παράδειγμαπαράδειγμαπαράδειγμαπαράδειγμαπαράδειγμαπα.com", - "valid": true - }, - { - "description": "label too long if separator ignored (ideographic full stop)", - "data": "παράδειγμαπαράδειγμαπαράδειγμαπαράδειγμαπαράδειγμαπα\u3002com", - "valid": true - }, - { - "description": "label too long if separator ignored (fullwidth full stop)", - "data": "παράδειγμαπαράδειγμαπαράδειγμαπαράδειγμαπαράδειγμαπα\uff0ecom", - "valid": true - }, - { - "description": "label too long if separator ignored (halfwidth ideographic full stop)", - "data": "παράδειγμαπαράδειγμαπαράδειγμαπαράδειγμαπαράδειγμαπα\uff61com", - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/ipv4.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/ipv4.json deleted file mode 100644 index 86d27bdb..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/ipv4.json +++ /dev/null @@ -1,92 +0,0 @@ -[ - { - "description": "validation of IP addresses", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "ipv4" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "a valid IP address", - "data": "192.168.0.1", - "valid": true - }, - { - "description": "an IP address with too many components", - "data": "127.0.0.0.1", - "valid": false - }, - { - "description": "an IP address with out-of-range values", - "data": "256.256.256.256", - "valid": false - }, - { - "description": "an IP address without 4 components", - "data": "127.0", - "valid": false - }, - { - "description": "an IP address as an integer", - "data": "0x7f000001", - "valid": false - }, - { - "description": "an IP address as an integer (decimal)", - "data": "2130706433", - "valid": false - }, - { - "description": "invalid leading zeroes, as they are treated as octals", - "comment": "see https://sick.codes/universal-netmask-npm-package-used-by-270000-projects-vulnerable-to-octal-input-data-server-side-request-forgery-remote-file-inclusion-local-file-inclusion-and-more-cve-2021-28918/", - "data": "087.10.0.1", - "valid": false - }, - { - "description": "value without leading zero is valid", - "data": "87.10.0.1", - "valid": true - }, - { - "description": "invalid non-ASCII '২' (a Bengali 2)", - "data": "1২7.0.0.1", - "valid": false - }, - { - "description": "netmask is not a part of ipv4 address", - "data": "192.168.1.0/24", - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/ipv6.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/ipv6.json deleted file mode 100644 index b9e570c9..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/ipv6.json +++ /dev/null @@ -1,211 +0,0 @@ -[ - { - "description": "validation of IPv6 addresses", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "ipv6" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "a valid IPv6 address", - "data": "::1", - "valid": true - }, - { - "description": "an IPv6 address with out-of-range values", - "data": "12345::", - "valid": false - }, - { - "description": "trailing 4 hex symbols is valid", - "data": "::abef", - "valid": true - }, - { - "description": "trailing 5 hex symbols is invalid", - "data": "::abcef", - "valid": false - }, - { - "description": "an IPv6 address with too many components", - "data": "1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1", - "valid": false - }, - { - "description": "an IPv6 address containing illegal characters", - "data": "::laptop", - "valid": false - }, - { - "description": "no digits is valid", - "data": "::", - "valid": true - }, - { - "description": "leading colons is valid", - "data": "::42:ff:1", - "valid": true - }, - { - "description": "trailing colons is valid", - "data": "d6::", - "valid": true - }, - { - "description": "missing leading octet is invalid", - "data": ":2:3:4:5:6:7:8", - "valid": false - }, - { - "description": "missing trailing octet is invalid", - "data": "1:2:3:4:5:6:7:", - "valid": false - }, - { - "description": "missing leading octet with omitted octets later", - "data": ":2:3:4::8", - "valid": false - }, - { - "description": "single set of double colons in the middle is valid", - "data": "1:d6::42", - "valid": true - }, - { - "description": "two sets of double colons is invalid", - "data": "1::d6::42", - "valid": false - }, - { - "description": "mixed format with the ipv4 section as decimal octets", - "data": "1::d6:192.168.0.1", - "valid": true - }, - { - "description": "mixed format with double colons between the sections", - "data": "1:2::192.168.0.1", - "valid": true - }, - { - "description": "mixed format with ipv4 section with octet out of range", - "data": "1::2:192.168.256.1", - "valid": false - }, - { - "description": "mixed format with ipv4 section with a hex octet", - "data": "1::2:192.168.ff.1", - "valid": false - }, - { - "description": "mixed format with leading double colons (ipv4-mapped ipv6 address)", - "data": "::ffff:192.168.0.1", - "valid": true - }, - { - "description": "triple colons is invalid", - "data": "1:2:3:4:5:::8", - "valid": false - }, - { - "description": "8 octets", - "data": "1:2:3:4:5:6:7:8", - "valid": true - }, - { - "description": "insufficient octets without double colons", - "data": "1:2:3:4:5:6:7", - "valid": false - }, - { - "description": "no colons is invalid", - "data": "1", - "valid": false - }, - { - "description": "ipv4 is not ipv6", - "data": "127.0.0.1", - "valid": false - }, - { - "description": "ipv4 segment must have 4 octets", - "data": "1:2:3:4:1.2.3", - "valid": false - }, - { - "description": "leading whitespace is invalid", - "data": " ::1", - "valid": false - }, - { - "description": "trailing whitespace is invalid", - "data": "::1 ", - "valid": false - }, - { - "description": "netmask is not a part of ipv6 address", - "data": "fe80::/64", - "valid": false - }, - { - "description": "zone id is not a part of ipv6 address", - "data": "fe80::a%eth1", - "valid": false - }, - { - "description": "a long valid ipv6", - "data": "1000:1000:1000:1000:1000:1000:255.255.255.255", - "valid": true - }, - { - "description": "a long invalid ipv6, below length limit, first", - "data": "100:100:100:100:100:100:255.255.255.255.255", - "valid": false - }, - { - "description": "a long invalid ipv6, below length limit, second", - "data": "100:100:100:100:100:100:100:255.255.255.255", - "valid": false - }, - { - "description": "invalid non-ASCII '৪' (a Bengali 4)", - "data": "1:2:3:4:5:6:7:৪", - "valid": false - }, - { - "description": "invalid non-ASCII '৪' (a Bengali 4) in the IPv4 portion", - "data": "1:2::192.16৪.0.1", - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/iri-reference.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/iri-reference.json deleted file mode 100644 index 0c9483dc..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/iri-reference.json +++ /dev/null @@ -1,76 +0,0 @@ -[ - { - "description": "validation of IRI References", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "iri-reference" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "a valid IRI", - "data": "http://ƒøø.ßår/?∂éœ=πîx#πîüx", - "valid": true - }, - { - "description": "a valid protocol-relative IRI Reference", - "data": "//ƒøø.ßår/?∂éœ=πîx#πîüx", - "valid": true - }, - { - "description": "a valid relative IRI Reference", - "data": "/âππ", - "valid": true - }, - { - "description": "an invalid IRI Reference", - "data": "\\\\WINDOWS\\filëßåré", - "valid": false - }, - { - "description": "a valid IRI Reference", - "data": "âππ", - "valid": true - }, - { - "description": "a valid IRI fragment", - "data": "#ƒrägmênt", - "valid": true - }, - { - "description": "an invalid IRI fragment", - "data": "#ƒräg\\mênt", - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/iri.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/iri.json deleted file mode 100644 index 311c9ef0..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/iri.json +++ /dev/null @@ -1,86 +0,0 @@ -[ - { - "description": "validation of IRIs", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "iri" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "a valid IRI with anchor tag", - "data": "http://ƒøø.ßår/?∂éœ=πîx#πîüx", - "valid": true - }, - { - "description": "a valid IRI with anchor tag and parentheses", - "data": "http://ƒøø.com/blah_(wîkïpédiå)_blah#ßité-1", - "valid": true - }, - { - "description": "a valid IRI with URL-encoded stuff", - "data": "http://ƒøø.ßår/?q=Test%20URL-encoded%20stuff", - "valid": true - }, - { - "description": "a valid IRI with many special characters", - "data": "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", - "valid": true - }, - { - "description": "a valid IRI based on IPv6", - "data": "http://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]", - "valid": true - }, - { - "description": "an invalid IRI based on IPv6", - "data": "http://2001:0db8:85a3:0000:0000:8a2e:0370:7334", - "valid": false - }, - { - "description": "an invalid relative IRI Reference", - "data": "/abc", - "valid": false - }, - { - "description": "an invalid IRI", - "data": "\\\\WINDOWS\\filëßåré", - "valid": false - }, - { - "description": "an invalid IRI though valid IRI reference", - "data": "âππ", - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/json-pointer.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/json-pointer.json deleted file mode 100644 index 71ba9b60..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/json-pointer.json +++ /dev/null @@ -1,201 +0,0 @@ -[ - { - "description": "validation of JSON-pointers (JSON String Representation)", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "json-pointer" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "a valid JSON-pointer", - "data": "/foo/bar~0/baz~1/%a", - "valid": true - }, - { - "description": "not a valid JSON-pointer (~ not escaped)", - "data": "/foo/bar~", - "valid": false - }, - { - "description": "valid JSON-pointer with empty segment", - "data": "/foo//bar", - "valid": true - }, - { - "description": "valid JSON-pointer with the last empty segment", - "data": "/foo/bar/", - "valid": true - }, - { - "description": "valid JSON-pointer as stated in RFC 6901 #1", - "data": "", - "valid": true - }, - { - "description": "valid JSON-pointer as stated in RFC 6901 #2", - "data": "/foo", - "valid": true - }, - { - "description": "valid JSON-pointer as stated in RFC 6901 #3", - "data": "/foo/0", - "valid": true - }, - { - "description": "valid JSON-pointer as stated in RFC 6901 #4", - "data": "/", - "valid": true - }, - { - "description": "valid JSON-pointer as stated in RFC 6901 #5", - "data": "/a~1b", - "valid": true - }, - { - "description": "valid JSON-pointer as stated in RFC 6901 #6", - "data": "/c%d", - "valid": true - }, - { - "description": "valid JSON-pointer as stated in RFC 6901 #7", - "data": "/e^f", - "valid": true - }, - { - "description": "valid JSON-pointer as stated in RFC 6901 #8", - "data": "/g|h", - "valid": true - }, - { - "description": "valid JSON-pointer as stated in RFC 6901 #9", - "data": "/i\\j", - "valid": true - }, - { - "description": "valid JSON-pointer as stated in RFC 6901 #10", - "data": "/k\"l", - "valid": true - }, - { - "description": "valid JSON-pointer as stated in RFC 6901 #11", - "data": "/ ", - "valid": true - }, - { - "description": "valid JSON-pointer as stated in RFC 6901 #12", - "data": "/m~0n", - "valid": true - }, - { - "description": "valid JSON-pointer used adding to the last array position", - "data": "/foo/-", - "valid": true - }, - { - "description": "valid JSON-pointer (- used as object member name)", - "data": "/foo/-/bar", - "valid": true - }, - { - "description": "valid JSON-pointer (multiple escaped characters)", - "data": "/~1~0~0~1~1", - "valid": true - }, - { - "description": "valid JSON-pointer (escaped with fraction part) #1", - "data": "/~1.1", - "valid": true - }, - { - "description": "valid JSON-pointer (escaped with fraction part) #2", - "data": "/~0.1", - "valid": true - }, - { - "description": "not a valid JSON-pointer (URI Fragment Identifier) #1", - "data": "#", - "valid": false - }, - { - "description": "not a valid JSON-pointer (URI Fragment Identifier) #2", - "data": "#/", - "valid": false - }, - { - "description": "not a valid JSON-pointer (URI Fragment Identifier) #3", - "data": "#a", - "valid": false - }, - { - "description": "not a valid JSON-pointer (some escaped, but not all) #1", - "data": "/~0~", - "valid": false - }, - { - "description": "not a valid JSON-pointer (some escaped, but not all) #2", - "data": "/~0/~", - "valid": false - }, - { - "description": "not a valid JSON-pointer (wrong escape character) #1", - "data": "/~2", - "valid": false - }, - { - "description": "not a valid JSON-pointer (wrong escape character) #2", - "data": "/~-1", - "valid": false - }, - { - "description": "not a valid JSON-pointer (multiple characters not escaped)", - "data": "/~~", - "valid": false - }, - { - "description": "not a valid JSON-pointer (isn't empty nor starts with /) #1", - "data": "a", - "valid": false - }, - { - "description": "not a valid JSON-pointer (isn't empty nor starts with /) #2", - "data": "0", - "valid": false - }, - { - "description": "not a valid JSON-pointer (isn't empty nor starts with /) #3", - "data": "a/a", - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/regex.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/regex.json deleted file mode 100644 index a036c6de..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/regex.json +++ /dev/null @@ -1,51 +0,0 @@ -[ - { - "description": "validation of regular expressions", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "regex" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "a valid regular expression", - "data": "([abc])+\\s+$", - "valid": true - }, - { - "description": "a regular expression with unclosed parens is invalid", - "data": "^(abc]", - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/relative-json-pointer.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/relative-json-pointer.json deleted file mode 100644 index 3eaf9ce2..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/relative-json-pointer.json +++ /dev/null @@ -1,101 +0,0 @@ -[ - { - "description": "validation of Relative JSON Pointers (RJP)", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "relative-json-pointer" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "a valid upwards RJP", - "data": "1", - "valid": true - }, - { - "description": "a valid downwards RJP", - "data": "0/foo/bar", - "valid": true - }, - { - "description": "a valid up and then down RJP, with array index", - "data": "2/0/baz/1/zip", - "valid": true - }, - { - "description": "a valid RJP taking the member or index name", - "data": "0#", - "valid": true - }, - { - "description": "an invalid RJP that is a valid JSON Pointer", - "data": "/foo/bar", - "valid": false - }, - { - "description": "negative prefix", - "data": "-1/foo/bar", - "valid": false - }, - { - "description": "explicit positive prefix", - "data": "+1/foo/bar", - "valid": false - }, - { - "description": "## is not a valid json-pointer", - "data": "0##", - "valid": false - }, - { - "description": "zero cannot be followed by other digits, plus json-pointer", - "data": "01/a", - "valid": false - }, - { - "description": "zero cannot be followed by other digits, plus octothorpe", - "data": "01#", - "valid": false - }, - { - "description": "empty string", - "data": "", - "valid": false - }, - { - "description": "multi-digit integer prefix", - "data": "120/foo/bar", - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/time.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/time.json deleted file mode 100644 index 88980ebb..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/time.json +++ /dev/null @@ -1,241 +0,0 @@ -[ - { - "description": "validation of time strings", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "time" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "a valid time string", - "data": "08:30:06Z", - "valid": true - }, - { - "description": "invalid time string with extra leading zeros", - "data": "008:030:006Z", - "valid": false - }, - { - "description": "invalid time string with no leading zero for single digit", - "data": "8:3:6Z", - "valid": false - }, - { - "description": "hour, minute, second must be two digits", - "data": "8:0030:6Z", - "valid": false - }, - { - "description": "a valid time string with leap second, Zulu", - "data": "23:59:60Z", - "valid": true - }, - { - "description": "invalid leap second, Zulu (wrong hour)", - "data": "22:59:60Z", - "valid": false - }, - { - "description": "invalid leap second, Zulu (wrong minute)", - "data": "23:58:60Z", - "valid": false - }, - { - "description": "valid leap second, zero time-offset", - "data": "23:59:60+00:00", - "valid": true - }, - { - "description": "invalid leap second, zero time-offset (wrong hour)", - "data": "22:59:60+00:00", - "valid": false - }, - { - "description": "invalid leap second, zero time-offset (wrong minute)", - "data": "23:58:60+00:00", - "valid": false - }, - { - "description": "valid leap second, positive time-offset", - "data": "01:29:60+01:30", - "valid": true - }, - { - "description": "valid leap second, large positive time-offset", - "data": "23:29:60+23:30", - "valid": true - }, - { - "description": "invalid leap second, positive time-offset (wrong hour)", - "data": "23:59:60+01:00", - "valid": false - }, - { - "description": "invalid leap second, positive time-offset (wrong minute)", - "data": "23:59:60+00:30", - "valid": false - }, - { - "description": "valid leap second, negative time-offset", - "data": "15:59:60-08:00", - "valid": true - }, - { - "description": "valid leap second, large negative time-offset", - "data": "00:29:60-23:30", - "valid": true - }, - { - "description": "invalid leap second, negative time-offset (wrong hour)", - "data": "23:59:60-01:00", - "valid": false - }, - { - "description": "invalid leap second, negative time-offset (wrong minute)", - "data": "23:59:60-00:30", - "valid": false - }, - { - "description": "a valid time string with second fraction", - "data": "23:20:50.52Z", - "valid": true - }, - { - "description": "a valid time string with precise second fraction", - "data": "08:30:06.283185Z", - "valid": true - }, - { - "description": "a valid time string with plus offset", - "data": "08:30:06+00:20", - "valid": true - }, - { - "description": "a valid time string with minus offset", - "data": "08:30:06-08:00", - "valid": true - }, - { - "description": "hour, minute in time-offset must be two digits", - "data": "08:30:06-8:000", - "valid": false - }, - { - "description": "a valid time string with case-insensitive Z", - "data": "08:30:06z", - "valid": true - }, - { - "description": "an invalid time string with invalid hour", - "data": "24:00:00Z", - "valid": false - }, - { - "description": "an invalid time string with invalid minute", - "data": "00:60:00Z", - "valid": false - }, - { - "description": "an invalid time string with invalid second", - "data": "00:00:61Z", - "valid": false - }, - { - "description": "an invalid time string with invalid leap second (wrong hour)", - "data": "22:59:60Z", - "valid": false - }, - { - "description": "an invalid time string with invalid leap second (wrong minute)", - "data": "23:58:60Z", - "valid": false - }, - { - "description": "an invalid time string with invalid time numoffset hour", - "data": "01:02:03+24:00", - "valid": false - }, - { - "description": "an invalid time string with invalid time numoffset minute", - "data": "01:02:03+00:60", - "valid": false - }, - { - "description": "an invalid time string with invalid time with both Z and numoffset", - "data": "01:02:03Z+00:30", - "valid": false - }, - { - "description": "an invalid offset indicator", - "data": "08:30:06 PST", - "valid": false - }, - { - "description": "only RFC3339 not all of ISO 8601 are valid", - "data": "01:01:01,1111", - "valid": false - }, - { - "description": "no time offset", - "data": "12:00:00", - "valid": false - }, - { - "description": "no time offset with second fraction", - "data": "12:00:00.52", - "valid": false - }, - { - "description": "invalid non-ASCII '২' (a Bengali 2)", - "data": "1২:00:00Z", - "valid": false - }, - { - "description": "offset not starting with plus or minus", - "data": "08:30:06#00:20", - "valid": false - }, - { - "description": "contains letters", - "data": "ab:cd:ef", - "valid": false - }, - { - "description": "an invalid time string in date-time format", - "data": "2020-11-28T23:55:45Z", - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/unknown.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/unknown.json deleted file mode 100644 index 7fc35f53..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/unknown.json +++ /dev/null @@ -1,46 +0,0 @@ -[ - { - "description": "unknown format", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "unknown" - }, - "tests": [ - { - "description": "unknown formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "unknown formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "unknown formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "unknown formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "unknown formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "unknown formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "unknown formats ignore strings", - "data": "string", - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/uri-reference.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/uri-reference.json deleted file mode 100644 index f7d04bb1..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/uri-reference.json +++ /dev/null @@ -1,86 +0,0 @@ -[ - { - "description": "validation of URI References", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "uri-reference" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "a valid URI", - "data": "http://foo.bar/?baz=qux#quux", - "valid": true - }, - { - "description": "a valid protocol-relative URI Reference", - "data": "//foo.bar/?baz=qux#quux", - "valid": true - }, - { - "description": "a valid relative URI Reference", - "data": "/abc", - "valid": true - }, - { - "description": "an invalid URI Reference", - "data": "\\\\WINDOWS\\fileshare", - "valid": false - }, - { - "description": "a valid URI Reference", - "data": "abc", - "valid": true - }, - { - "description": "a valid URI fragment", - "data": "#fragment", - "valid": true - }, - { - "description": "an invalid URI fragment", - "data": "#frag\\ment", - "valid": false - }, - { - "description": "unescaped non US-ASCII characters", - "data": "/foobar®.txt", - "valid": false - }, - { - "description": "invalid backslash character", - "data": "https://example.org/foobar\\.txt", - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/uri-template.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/uri-template.json deleted file mode 100644 index 08aab829..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/uri-template.json +++ /dev/null @@ -1,61 +0,0 @@ -[ - { - "description": "format: uri-template", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "uri-template" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "a valid uri-template", - "data": "http://example.com/dictionary/{term:1}/{term}", - "valid": true - }, - { - "description": "an invalid uri-template", - "data": "http://example.com/dictionary/{term:1}/{term", - "valid": false - }, - { - "description": "a valid uri-template without variables", - "data": "http://example.com/dictionary", - "valid": true - }, - { - "description": "a valid relative uri-template", - "data": "dictionary/{term:1}/{term}", - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/uri.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/uri.json deleted file mode 100644 index 24faebf3..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/uri.json +++ /dev/null @@ -1,191 +0,0 @@ -[ - { - "description": "validation of URIs", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "uri" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "a valid URL with anchor tag", - "data": "http://foo.bar/?baz=qux#quux", - "valid": true - }, - { - "description": "a valid URL with anchor tag and parentheses", - "data": "http://foo.com/blah_(wikipedia)_blah#cite-1", - "valid": true - }, - { - "description": "a valid URL with URL-encoded stuff", - "data": "http://foo.bar/?q=Test%20URL-encoded%20stuff", - "valid": true - }, - { - "description": "a valid puny-coded URL ", - "data": "http://xn--nw2a.xn--j6w193g/", - "valid": true - }, - { - "description": "a valid URL with many special characters", - "data": "http://-.~_!$&'()*+,;=:%40:80%2f::::::@example.com", - "valid": true - }, - { - "description": "a valid URL based on IPv4", - "data": "http://223.255.255.254", - "valid": true - }, - { - "description": "a valid URL with ftp scheme", - "data": "ftp://ftp.is.co.za/rfc/rfc1808.txt", - "valid": true - }, - { - "description": "a valid URL for a simple text file", - "data": "http://www.ietf.org/rfc/rfc2396.txt", - "valid": true - }, - { - "description": "a valid URL ", - "data": "ldap://[2001:db8::7]/c=GB?objectClass?one", - "valid": true - }, - { - "description": "a valid mailto URI", - "data": "mailto:John.Doe@example.com", - "valid": true - }, - { - "description": "a valid newsgroup URI", - "data": "news:comp.infosystems.www.servers.unix", - "valid": true - }, - { - "description": "a valid tel URI", - "data": "tel:+1-816-555-1212", - "valid": true - }, - { - "description": "a valid URN", - "data": "urn:oasis:names:specification:docbook:dtd:xml:4.1.2", - "valid": true - }, - { - "description": "an invalid protocol-relative URI Reference", - "data": "//foo.bar/?baz=qux#quux", - "valid": false - }, - { - "description": "an invalid relative URI Reference", - "data": "/abc", - "valid": false - }, - { - "description": "an invalid URI", - "data": "\\\\WINDOWS\\fileshare", - "valid": false - }, - { - "description": "an invalid URI though valid URI reference", - "data": "abc", - "valid": false - }, - { - "description": "an invalid URI with spaces", - "data": "http:// shouldfail.com", - "valid": false - }, - { - "description": "an invalid URI with spaces and missing scheme", - "data": ":// should fail", - "valid": false - }, - { - "description": "an invalid URI with comma in scheme", - "data": "bar,baz:foo", - "valid": false - }, - { - "description": "invalid userinfo", - "data": "https://[@example.org/test.txt", - "valid": false - }, - { - "description": "unescaped non US-ASCII characters", - "data": "https://example.org/foobar®.txt", - "valid": false - }, - { - "description": "invalid backslash character", - "data": "https://example.org/foobar\\.txt", - "valid": false - }, - { - "description": "invalid \" character", - "data": "https://example.org/foobar\".txt", - "valid": false - }, - { - "description": "invalid <> characters", - "data": "https://example.org/foobar<>.txt", - "valid": false - }, - { - "description": "invalid {} characters", - "data": "https://example.org/foobar{}.txt", - "valid": false - }, - { - "description": "invalid ^ character", - "data": "https://example.org/foobar^.txt", - "valid": false - }, - { - "description": "invalid ` character", - "data": "https://example.org/foobar`.txt", - "valid": false - }, - { - "description": "invalid SPACE character", - "data": "https://example.org/foo bar.txt", - "valid": false - }, - { - "description": "invalid | character", - "data": "https://example.org/foobar|.txt", - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/uuid.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/uuid.json deleted file mode 100644 index 3baa9013..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/format/uuid.json +++ /dev/null @@ -1,121 +0,0 @@ -[ - { - "description": "uuid format", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "format": "uuid" - }, - "tests": [ - { - "description": "all string formats ignore integers", - "data": 12, - "valid": true - }, - { - "description": "all string formats ignore floats", - "data": 13.7, - "valid": true - }, - { - "description": "all string formats ignore objects", - "data": {}, - "valid": true - }, - { - "description": "all string formats ignore arrays", - "data": [], - "valid": true - }, - { - "description": "all string formats ignore booleans", - "data": false, - "valid": true - }, - { - "description": "all string formats ignore nulls", - "data": null, - "valid": true - }, - { - "description": "all upper-case", - "data": "2EB8AA08-AA98-11EA-B4AA-73B441D16380", - "valid": true - }, - { - "description": "all lower-case", - "data": "2eb8aa08-aa98-11ea-b4aa-73b441d16380", - "valid": true - }, - { - "description": "mixed case", - "data": "2eb8aa08-AA98-11ea-B4Aa-73B441D16380", - "valid": true - }, - { - "description": "all zeroes is valid", - "data": "00000000-0000-0000-0000-000000000000", - "valid": true - }, - { - "description": "wrong length", - "data": "2eb8aa08-aa98-11ea-b4aa-73b441d1638", - "valid": false - }, - { - "description": "missing section", - "data": "2eb8aa08-aa98-11ea-73b441d16380", - "valid": false - }, - { - "description": "bad characters (not hex)", - "data": "2eb8aa08-aa98-11ea-b4ga-73b441d16380", - "valid": false - }, - { - "description": "no dashes", - "data": "2eb8aa08aa9811eab4aa73b441d16380", - "valid": false - }, - { - "description": "too few dashes", - "data": "2eb8aa08aa98-11ea-b4aa73b441d16380", - "valid": false - }, - { - "description": "too many dashes", - "data": "2eb8-aa08-aa98-11ea-b4aa73b44-1d16380", - "valid": false - }, - { - "description": "dashes in the wrong spot", - "data": "2eb8aa08aa9811eab4aa73b441d16380----", - "valid": false - }, - { - "description": "shifted dashes", - "data": "2eb8aa0-8aa98-11e-ab4aa7-3b441d16380", - "valid": false - }, - { - "description": "valid version 4", - "data": "98d80576-482e-427f-8434-7f86890ab222", - "valid": true - }, - { - "description": "valid version 5", - "data": "99c17cbb-656f-564a-940f-1a4568f03487", - "valid": true - }, - { - "description": "hypothetical version 6", - "data": "99c17cbb-656f-664a-940f-1a4568f03487", - "valid": true - }, - { - "description": "hypothetical version 15", - "data": "99c17cbb-656f-f64a-940f-1a4568f03487", - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/id.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/id.json deleted file mode 100644 index 0b7df4e8..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/id.json +++ /dev/null @@ -1,53 +0,0 @@ -[ - { - "description": "$id inside an enum is not a real identifier", - "comment": "the implementation must not be confused by an $id buried in the enum", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$defs": { - "id_in_enum": { - "enum": [ - { - "$id": "https://localhost:1234/draft2020-12/id/my_identifier.json", - "type": "null" - } - ] - }, - "real_id_in_schema": { - "$id": "https://localhost:1234/draft2020-12/id/my_identifier.json", - "type": "string" - }, - "zzz_id_in_const": { - "const": { - "$id": "https://localhost:1234/draft2020-12/id/my_identifier.json", - "type": "null" - } - } - }, - "anyOf": [ - { "$ref": "#/$defs/id_in_enum" }, - { "$ref": "https://localhost:1234/draft2020-12/id/my_identifier.json" } - ] - }, - "tests": [ - { - "description": "exact match to enum, and type matches", - "data": { - "$id": "https://localhost:1234/draft2020-12/id/my_identifier.json", - "type": "null" - }, - "valid": true - }, - { - "description": "match $ref to $id", - "data": "a string to match #/$defs/id_in_enum", - "valid": true - }, - { - "description": "no match on enum or $ref to $id", - "data": 1, - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/no-schema.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/no-schema.json deleted file mode 100644 index 676e6b53..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/no-schema.json +++ /dev/null @@ -1,26 +0,0 @@ -[ - { - "description": "validation without $schema", - "comment": "minLength is the same across all drafts", - "schema": { - "minLength": 2 - }, - "tests": [ - { - "description": "a 3-character string is valid", - "data": "foo", - "valid": true - }, - { - "description": "a 1-character string is not valid", - "data": "a", - "valid": false - }, - { - "description": "a non-string is valid", - "data": 5, - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/non-bmp-regex.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/non-bmp-regex.json deleted file mode 100644 index d2efb3ef..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/non-bmp-regex.json +++ /dev/null @@ -1,86 +0,0 @@ -[ - { - "description": "Proper UTF-16 surrogate pair handling: pattern", - "comment": "Optional because .Net doesn't correctly handle 32-bit Unicode characters", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "pattern": "^🐲*$" - }, - "tests": [ - { - "description": "matches empty", - "data": "", - "valid": true - }, - { - "description": "matches single", - "data": "🐲", - "valid": true - }, - { - "description": "matches two", - "data": "🐲🐲", - "valid": true - }, - { - "description": "doesn't match one", - "data": "🐉", - "valid": false - }, - { - "description": "doesn't match two", - "data": "🐉🐉", - "valid": false - }, - { - "description": "doesn't match one ASCII", - "data": "D", - "valid": false - }, - { - "description": "doesn't match two ASCII", - "data": "DD", - "valid": false - } - ] - }, - { - "description": "Proper UTF-16 surrogate pair handling: patternProperties", - "comment": "Optional because .Net doesn't correctly handle 32-bit Unicode characters", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "patternProperties": { - "^🐲*$": { - "type": "integer" - } - } - }, - "tests": [ - { - "description": "matches empty", - "data": { "": 1 }, - "valid": true - }, - { - "description": "matches single", - "data": { "🐲": 1 }, - "valid": true - }, - { - "description": "matches two", - "data": { "🐲🐲": 1 }, - "valid": true - }, - { - "description": "doesn't match one", - "data": { "🐲": "hello" }, - "valid": false - }, - { - "description": "doesn't match two", - "data": { "🐲🐲": "hello" }, - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/refOfUnknownKeyword.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/refOfUnknownKeyword.json deleted file mode 100644 index 8276affe..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/refOfUnknownKeyword.json +++ /dev/null @@ -1,113 +0,0 @@ -[ - { - "description": "reference of a root arbitrary keyword ", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "unknown-keyword": {"type": "integer"}, - "properties": { - "bar": {"$ref": "#/unknown-keyword"} - } - }, - "tests": [ - { - "description": "match", - "data": {"bar": 3}, - "valid": true - }, - { - "description": "mismatch", - "data": {"bar": true}, - "valid": false - } - ] - }, - { - "description": "reference of a root arbitrary keyword with encoded ref", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "unknown/keyword": {"type": "integer"}, - "properties": { - "bar": {"$ref": "#/unknown~1keyword"} - } - }, - "tests": [ - { - "description": "match", - "data": {"bar": 3}, - "valid": true - }, - { - "description": "mismatch", - "data": {"bar": true}, - "valid": false - } - ] - }, - { - "description": "reference of an arbitrary keyword of a sub-schema", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": {"unknown-keyword": {"type": "integer"}}, - "bar": {"$ref": "#/properties/foo/unknown-keyword"} - } - }, - "tests": [ - { - "description": "match", - "data": {"bar": 3}, - "valid": true - }, - { - "description": "mismatch", - "data": {"bar": true}, - "valid": false - } - ] - }, - { - "description": "reference internals of known non-applicator", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "/base", - "examples": [ - { "type": "string" } - ], - "$ref": "#/examples/0" - }, - "tests": [ - { - "description": "match", - "data": "a string", - "valid": true - }, - { - "description": "mismatch", - "data": 42, - "valid": false - } - ] - }, - { - "description": "reference of an arbitrary keyword of a sub-schema with encoded ref", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": {"unknown/keyword": {"type": "integer"}}, - "bar": {"$ref": "#/properties/foo/unknown~1keyword"} - } - }, - "tests": [ - { - "description": "match", - "data": {"bar": 3}, - "valid": true - }, - { - "description": "mismatch", - "data": {"bar": true}, - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/unknownKeyword.json b/tests/fixtures/json-schema-test-suite/draft2020-12/optional/unknownKeyword.json deleted file mode 100644 index 28b0c4ce..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/optional/unknownKeyword.json +++ /dev/null @@ -1,57 +0,0 @@ -[ - { - "description": "$id inside an unknown keyword is not a real identifier", - "comment": "the implementation must not be confused by an $id in locations we do not know how to parse", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$defs": { - "id_in_unknown0": { - "not": { - "array_of_schemas": [ - { - "$id": "https://localhost:1234/draft2020-12/unknownKeyword/my_identifier.json", - "type": "null" - } - ] - } - }, - "real_id_in_schema": { - "$id": "https://localhost:1234/draft2020-12/unknownKeyword/my_identifier.json", - "type": "string" - }, - "id_in_unknown1": { - "not": { - "object_of_schemas": { - "foo": { - "$id": "https://localhost:1234/draft2020-12/unknownKeyword/my_identifier.json", - "type": "integer" - } - } - } - } - }, - "anyOf": [ - { "$ref": "#/$defs/id_in_unknown0" }, - { "$ref": "#/$defs/id_in_unknown1" }, - { "$ref": "https://localhost:1234/draft2020-12/unknownKeyword/my_identifier.json" } - ] - }, - "tests": [ - { - "description": "type matches second anyOf, which has a real schema in it", - "data": "a string", - "valid": true - }, - { - "description": "type matches non-schema in first anyOf", - "data": null, - "valid": false - }, - { - "description": "type matches non-schema in third anyOf", - "data": 1, - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/pattern.json b/tests/fixtures/json-schema-test-suite/draft2020-12/pattern.json deleted file mode 100644 index af0b8d89..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/pattern.json +++ /dev/null @@ -1,65 +0,0 @@ -[ - { - "description": "pattern validation", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "pattern": "^a*$" - }, - "tests": [ - { - "description": "a matching pattern is valid", - "data": "aaa", - "valid": true - }, - { - "description": "a non-matching pattern is invalid", - "data": "abc", - "valid": false - }, - { - "description": "ignores booleans", - "data": true, - "valid": true - }, - { - "description": "ignores integers", - "data": 123, - "valid": true - }, - { - "description": "ignores floats", - "data": 1.0, - "valid": true - }, - { - "description": "ignores objects", - "data": {}, - "valid": true - }, - { - "description": "ignores arrays", - "data": [], - "valid": true - }, - { - "description": "ignores null", - "data": null, - "valid": true - } - ] - }, - { - "description": "pattern is not anchored", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "pattern": "a+" - }, - "tests": [ - { - "description": "matches a substring", - "data": "xxaayy", - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/patternProperties.json b/tests/fixtures/json-schema-test-suite/draft2020-12/patternProperties.json deleted file mode 100644 index 81829c71..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/patternProperties.json +++ /dev/null @@ -1,176 +0,0 @@ -[ - { - "description": - "patternProperties validates properties matching a regex", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "patternProperties": { - "f.*o": {"type": "integer"} - } - }, - "tests": [ - { - "description": "a single valid match is valid", - "data": {"foo": 1}, - "valid": true - }, - { - "description": "multiple valid matches is valid", - "data": {"foo": 1, "foooooo" : 2}, - "valid": true - }, - { - "description": "a single invalid match is invalid", - "data": {"foo": "bar", "fooooo": 2}, - "valid": false - }, - { - "description": "multiple invalid matches is invalid", - "data": {"foo": "bar", "foooooo" : "baz"}, - "valid": false - }, - { - "description": "ignores arrays", - "data": ["foo"], - "valid": true - }, - { - "description": "ignores strings", - "data": "foo", - "valid": true - }, - { - "description": "ignores other non-objects", - "data": 12, - "valid": true - } - ] - }, - { - "description": "multiple simultaneous patternProperties are validated", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "patternProperties": { - "a*": {"type": "integer"}, - "aaa*": {"maximum": 20} - } - }, - "tests": [ - { - "description": "a single valid match is valid", - "data": {"a": 21}, - "valid": true - }, - { - "description": "a simultaneous match is valid", - "data": {"aaaa": 18}, - "valid": true - }, - { - "description": "multiple matches is valid", - "data": {"a": 21, "aaaa": 18}, - "valid": true - }, - { - "description": "an invalid due to one is invalid", - "data": {"a": "bar"}, - "valid": false - }, - { - "description": "an invalid due to the other is invalid", - "data": {"aaaa": 31}, - "valid": false - }, - { - "description": "an invalid due to both is invalid", - "data": {"aaa": "foo", "aaaa": 31}, - "valid": false - } - ] - }, - { - "description": "regexes are not anchored by default and are case sensitive", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "patternProperties": { - "[0-9]{2,}": { "type": "boolean" }, - "X_": { "type": "string" } - } - }, - "tests": [ - { - "description": "non recognized members are ignored", - "data": { "answer 1": "42" }, - "valid": true - }, - { - "description": "recognized members are accounted for", - "data": { "a31b": null }, - "valid": false - }, - { - "description": "regexes are case sensitive", - "data": { "a_x_3": 3 }, - "valid": true - }, - { - "description": "regexes are case sensitive, 2", - "data": { "a_X_3": 3 }, - "valid": false - } - ] - }, - { - "description": "patternProperties with boolean schemas", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "patternProperties": { - "f.*": true, - "b.*": false - } - }, - "tests": [ - { - "description": "object with property matching schema true is valid", - "data": {"foo": 1}, - "valid": true - }, - { - "description": "object with property matching schema false is invalid", - "data": {"bar": 2}, - "valid": false - }, - { - "description": "object with both properties is invalid", - "data": {"foo": 1, "bar": 2}, - "valid": false - }, - { - "description": "object with a property matching both true and false is invalid", - "data": {"foobar":1}, - "valid": false - }, - { - "description": "empty object is valid", - "data": {}, - "valid": true - } - ] - }, - { - "description": "patternProperties with null valued instance properties", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "patternProperties": { - "^.*bar$": {"type": "null"} - } - }, - "tests": [ - { - "description": "allows null values", - "data": {"foobar": null}, - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/prefixItems.json b/tests/fixtures/json-schema-test-suite/draft2020-12/prefixItems.json deleted file mode 100644 index 0adfc069..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/prefixItems.json +++ /dev/null @@ -1,104 +0,0 @@ -[ - { - "description": "a schema given for prefixItems", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "prefixItems": [ - {"type": "integer"}, - {"type": "string"} - ] - }, - "tests": [ - { - "description": "correct types", - "data": [ 1, "foo" ], - "valid": true - }, - { - "description": "wrong types", - "data": [ "foo", 1 ], - "valid": false - }, - { - "description": "incomplete array of items", - "data": [ 1 ], - "valid": true - }, - { - "description": "array with additional items", - "data": [ 1, "foo", true ], - "valid": true - }, - { - "description": "empty array", - "data": [ ], - "valid": true - }, - { - "description": "JavaScript pseudo-array is valid", - "data": { - "0": "invalid", - "1": "valid", - "length": 2 - }, - "valid": true - } - ] - }, - { - "description": "prefixItems with boolean schemas", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "prefixItems": [true, false] - }, - "tests": [ - { - "description": "array with one item is valid", - "data": [ 1 ], - "valid": true - }, - { - "description": "array with two items is invalid", - "data": [ 1, "foo" ], - "valid": false - }, - { - "description": "empty array is valid", - "data": [], - "valid": true - } - ] - }, - { - "description": "additional items are allowed by default", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "prefixItems": [{"type": "integer"}] - }, - "tests": [ - { - "description": "only the first item is validated", - "data": [1, "foo", false], - "valid": true - } - ] - }, - { - "description": "prefixItems with null instance elements", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "prefixItems": [ - { - "type": "null" - } - ] - }, - "tests": [ - { - "description": "allows null elements", - "data": [ null ], - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/properties.json b/tests/fixtures/json-schema-test-suite/draft2020-12/properties.json deleted file mode 100644 index eb66fa8b..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/properties.json +++ /dev/null @@ -1,242 +0,0 @@ -[ - { - "description": "object properties validation", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": {"type": "integer"}, - "bar": {"type": "string"} - } - }, - "tests": [ - { - "description": "both properties present and valid is valid", - "data": {"foo": 1, "bar": "baz"}, - "valid": true - }, - { - "description": "one property invalid is invalid", - "data": {"foo": 1, "bar": {}}, - "valid": false - }, - { - "description": "both properties invalid is invalid", - "data": {"foo": [], "bar": {}}, - "valid": false - }, - { - "description": "doesn't invalidate other properties", - "data": {"quux": []}, - "valid": true - }, - { - "description": "ignores arrays", - "data": [], - "valid": true - }, - { - "description": "ignores other non-objects", - "data": 12, - "valid": true - } - ] - }, - { - "description": - "properties, patternProperties, additionalProperties interaction", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": {"type": "array", "maxItems": 3}, - "bar": {"type": "array"} - }, - "patternProperties": {"f.o": {"minItems": 2}}, - "additionalProperties": {"type": "integer"} - }, - "tests": [ - { - "description": "property validates property", - "data": {"foo": [1, 2]}, - "valid": true - }, - { - "description": "property invalidates property", - "data": {"foo": [1, 2, 3, 4]}, - "valid": false - }, - { - "description": "patternProperty invalidates property", - "data": {"foo": []}, - "valid": false - }, - { - "description": "patternProperty validates nonproperty", - "data": {"fxo": [1, 2]}, - "valid": true - }, - { - "description": "patternProperty invalidates nonproperty", - "data": {"fxo": []}, - "valid": false - }, - { - "description": "additionalProperty ignores property", - "data": {"bar": []}, - "valid": true - }, - { - "description": "additionalProperty validates others", - "data": {"quux": 3}, - "valid": true - }, - { - "description": "additionalProperty invalidates others", - "data": {"quux": "foo"}, - "valid": false - } - ] - }, - { - "description": "properties with boolean schema", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": true, - "bar": false - } - }, - "tests": [ - { - "description": "no property present is valid", - "data": {}, - "valid": true - }, - { - "description": "only 'true' property present is valid", - "data": {"foo": 1}, - "valid": true - }, - { - "description": "only 'false' property present is invalid", - "data": {"bar": 2}, - "valid": false - }, - { - "description": "both properties present is invalid", - "data": {"foo": 1, "bar": 2}, - "valid": false - } - ] - }, - { - "description": "properties with escaped characters", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo\nbar": {"type": "number"}, - "foo\"bar": {"type": "number"}, - "foo\\bar": {"type": "number"}, - "foo\rbar": {"type": "number"}, - "foo\tbar": {"type": "number"}, - "foo\fbar": {"type": "number"} - } - }, - "tests": [ - { - "description": "object with all numbers is valid", - "data": { - "foo\nbar": 1, - "foo\"bar": 1, - "foo\\bar": 1, - "foo\rbar": 1, - "foo\tbar": 1, - "foo\fbar": 1 - }, - "valid": true - }, - { - "description": "object with strings is invalid", - "data": { - "foo\nbar": "1", - "foo\"bar": "1", - "foo\\bar": "1", - "foo\rbar": "1", - "foo\tbar": "1", - "foo\fbar": "1" - }, - "valid": false - } - ] - }, - { - "description": "properties with null valued instance properties", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": {"type": "null"} - } - }, - "tests": [ - { - "description": "allows null values", - "data": {"foo": null}, - "valid": true - } - ] - }, - { - "description": "properties whose names are Javascript object property names", - "comment": "Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object.", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "__proto__": {"type": "number"}, - "toString": { - "properties": { "length": { "type": "string" } } - }, - "constructor": {"type": "number"} - } - }, - "tests": [ - { - "description": "ignores arrays", - "data": [], - "valid": true - }, - { - "description": "ignores other non-objects", - "data": 12, - "valid": true - }, - { - "description": "none of the properties mentioned", - "data": {}, - "valid": true - }, - { - "description": "__proto__ not valid", - "data": { "__proto__": "foo" }, - "valid": false - }, - { - "description": "toString not valid", - "data": { "toString": { "length": 37 } }, - "valid": false - }, - { - "description": "constructor not valid", - "data": { "constructor": { "length": 37 } }, - "valid": false - }, - { - "description": "all present and valid", - "data": { - "__proto__": 12, - "toString": { "length": "foo" }, - "constructor": 37 - }, - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/propertyNames.json b/tests/fixtures/json-schema-test-suite/draft2020-12/propertyNames.json deleted file mode 100644 index b4780088..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/propertyNames.json +++ /dev/null @@ -1,168 +0,0 @@ -[ - { - "description": "propertyNames validation", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "propertyNames": {"maxLength": 3} - }, - "tests": [ - { - "description": "all property names valid", - "data": { - "f": {}, - "foo": {} - }, - "valid": true - }, - { - "description": "some property names invalid", - "data": { - "foo": {}, - "foobar": {} - }, - "valid": false - }, - { - "description": "object without properties is valid", - "data": {}, - "valid": true - }, - { - "description": "ignores arrays", - "data": [1, 2, 3, 4], - "valid": true - }, - { - "description": "ignores strings", - "data": "foobar", - "valid": true - }, - { - "description": "ignores other non-objects", - "data": 12, - "valid": true - } - ] - }, - { - "description": "propertyNames validation with pattern", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "propertyNames": { "pattern": "^a+$" } - }, - "tests": [ - { - "description": "matching property names valid", - "data": { - "a": {}, - "aa": {}, - "aaa": {} - }, - "valid": true - }, - { - "description": "non-matching property name is invalid", - "data": { - "aaA": {} - }, - "valid": false - }, - { - "description": "object without properties is valid", - "data": {}, - "valid": true - } - ] - }, - { - "description": "propertyNames with boolean schema true", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "propertyNames": true - }, - "tests": [ - { - "description": "object with any properties is valid", - "data": {"foo": 1}, - "valid": true - }, - { - "description": "empty object is valid", - "data": {}, - "valid": true - } - ] - }, - { - "description": "propertyNames with boolean schema false", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "propertyNames": false - }, - "tests": [ - { - "description": "object with any properties is invalid", - "data": {"foo": 1}, - "valid": false - }, - { - "description": "empty object is valid", - "data": {}, - "valid": true - } - ] - }, - { - "description": "propertyNames with const", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "propertyNames": {"const": "foo"} - }, - "tests": [ - { - "description": "object with property foo is valid", - "data": {"foo": 1}, - "valid": true - }, - { - "description": "object with any other property is invalid", - "data": {"bar": 1}, - "valid": false - }, - { - "description": "empty object is valid", - "data": {}, - "valid": true - } - ] - }, - { - "description": "propertyNames with enum", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "propertyNames": {"enum": ["foo", "bar"]} - }, - "tests": [ - { - "description": "object with property foo is valid", - "data": {"foo": 1}, - "valid": true - }, - { - "description": "object with property foo and bar is valid", - "data": {"foo": 1, "bar": 1}, - "valid": true - }, - { - "description": "object with any other property is invalid", - "data": {"baz": 1}, - "valid": false - }, - { - "description": "empty object is valid", - "data": {}, - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/ref.json b/tests/fixtures/json-schema-test-suite/draft2020-12/ref.json deleted file mode 100644 index 9ca82eeb..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/ref.json +++ /dev/null @@ -1,1085 +0,0 @@ -[ - { - "description": "root pointer ref", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": {"$ref": "#"} - }, - "additionalProperties": false - }, - "tests": [ - { - "description": "match", - "data": {"foo": false}, - "valid": true - }, - { - "description": "recursive match", - "data": {"foo": {"foo": false}}, - "valid": true - }, - { - "description": "mismatch", - "data": {"bar": false}, - "valid": false - }, - { - "description": "recursive mismatch", - "data": {"foo": {"bar": false}}, - "valid": false - } - ] - }, - { - "description": "relative pointer ref to object", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": {"type": "integer"}, - "bar": {"$ref": "#/properties/foo"} - } - }, - "tests": [ - { - "description": "match", - "data": {"bar": 3}, - "valid": true - }, - { - "description": "mismatch", - "data": {"bar": true}, - "valid": false - } - ] - }, - { - "description": "relative pointer ref to array", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "prefixItems": [ - {"type": "integer"}, - {"$ref": "#/prefixItems/0"} - ] - }, - "tests": [ - { - "description": "match array", - "data": [1, 2], - "valid": true - }, - { - "description": "mismatch array", - "data": [1, "foo"], - "valid": false - } - ] - }, - { - "description": "escaped pointer ref", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$defs": { - "tilde~field": {"type": "integer"}, - "slash/field": {"type": "integer"}, - "percent%field": {"type": "integer"} - }, - "properties": { - "tilde": {"$ref": "#/$defs/tilde~0field"}, - "slash": {"$ref": "#/$defs/slash~1field"}, - "percent": {"$ref": "#/$defs/percent%25field"} - } - }, - "tests": [ - { - "description": "slash invalid", - "data": {"slash": "aoeu"}, - "valid": false - }, - { - "description": "tilde invalid", - "data": {"tilde": "aoeu"}, - "valid": false - }, - { - "description": "percent invalid", - "data": {"percent": "aoeu"}, - "valid": false - }, - { - "description": "slash valid", - "data": {"slash": 123}, - "valid": true - }, - { - "description": "tilde valid", - "data": {"tilde": 123}, - "valid": true - }, - { - "description": "percent valid", - "data": {"percent": 123}, - "valid": true - } - ] - }, - { - "description": "nested refs", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$defs": { - "a": {"type": "integer"}, - "b": {"$ref": "#/$defs/a"}, - "c": {"$ref": "#/$defs/b"} - }, - "$ref": "#/$defs/c" - }, - "tests": [ - { - "description": "nested ref valid", - "data": 5, - "valid": true - }, - { - "description": "nested ref invalid", - "data": "a", - "valid": false - } - ] - }, - { - "description": "ref applies alongside sibling keywords", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$defs": { - "reffed": { - "type": "array" - } - }, - "properties": { - "foo": { - "$ref": "#/$defs/reffed", - "maxItems": 2 - } - } - }, - "tests": [ - { - "description": "ref valid, maxItems valid", - "data": { "foo": [] }, - "valid": true - }, - { - "description": "ref valid, maxItems invalid", - "data": { "foo": [1, 2, 3] }, - "valid": false - }, - { - "description": "ref invalid", - "data": { "foo": "string" }, - "valid": false - } - ] - }, - { - "description": "remote ref, containing refs itself", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$ref": "https://json-schema.org/draft/2020-12/schema" - }, - "tests": [ - { - "description": "remote ref valid", - "data": {"minLength": 1}, - "valid": true - }, - { - "description": "remote ref invalid", - "data": {"minLength": -1}, - "valid": false - } - ] - }, - { - "description": "property named $ref that is not a reference", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "$ref": {"type": "string"} - } - }, - "tests": [ - { - "description": "property named $ref valid", - "data": {"$ref": "a"}, - "valid": true - }, - { - "description": "property named $ref invalid", - "data": {"$ref": 2}, - "valid": false - } - ] - }, - { - "description": "property named $ref, containing an actual $ref", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "$ref": {"$ref": "#/$defs/is-string"} - }, - "$defs": { - "is-string": { - "type": "string" - } - } - }, - "tests": [ - { - "description": "property named $ref valid", - "data": {"$ref": "a"}, - "valid": true - }, - { - "description": "property named $ref invalid", - "data": {"$ref": 2}, - "valid": false - } - ] - }, - { - "description": "$ref to boolean schema true", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$ref": "#/$defs/bool", - "$defs": { - "bool": true - } - }, - "tests": [ - { - "description": "any value is valid", - "data": "foo", - "valid": true - } - ] - }, - { - "description": "$ref to boolean schema false", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$ref": "#/$defs/bool", - "$defs": { - "bool": false - } - }, - "tests": [ - { - "description": "any value is invalid", - "data": "foo", - "valid": false - } - ] - }, - { - "description": "Recursive references between schemas", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "http://localhost:1234/draft2020-12/tree", - "description": "tree of nodes", - "type": "object", - "properties": { - "meta": {"type": "string"}, - "nodes": { - "type": "array", - "items": {"$ref": "node"} - } - }, - "required": ["meta", "nodes"], - "$defs": { - "node": { - "$id": "http://localhost:1234/draft2020-12/node", - "description": "node", - "type": "object", - "properties": { - "value": {"type": "number"}, - "subtree": {"$ref": "tree"} - }, - "required": ["value"] - } - } - }, - "tests": [ - { - "description": "valid tree", - "data": { - "meta": "root", - "nodes": [ - { - "value": 1, - "subtree": { - "meta": "child", - "nodes": [ - {"value": 1.1}, - {"value": 1.2} - ] - } - }, - { - "value": 2, - "subtree": { - "meta": "child", - "nodes": [ - {"value": 2.1}, - {"value": 2.2} - ] - } - } - ] - }, - "valid": true - }, - { - "description": "invalid tree", - "data": { - "meta": "root", - "nodes": [ - { - "value": 1, - "subtree": { - "meta": "child", - "nodes": [ - {"value": "string is invalid"}, - {"value": 1.2} - ] - } - }, - { - "value": 2, - "subtree": { - "meta": "child", - "nodes": [ - {"value": 2.1}, - {"value": 2.2} - ] - } - } - ] - }, - "valid": false - } - ] - }, - { - "description": "refs with quote", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo\"bar": {"$ref": "#/$defs/foo%22bar"} - }, - "$defs": { - "foo\"bar": {"type": "number"} - } - }, - "tests": [ - { - "description": "object with numbers is valid", - "data": { - "foo\"bar": 1 - }, - "valid": true - }, - { - "description": "object with strings is invalid", - "data": { - "foo\"bar": "1" - }, - "valid": false - } - ] - }, - { - "description": "ref creates new scope when adjacent to keywords", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$defs": { - "A": { - "unevaluatedProperties": false - } - }, - "properties": { - "prop1": { - "type": "string" - } - }, - "$ref": "#/$defs/A" - }, - "tests": [ - { - "description": "referenced subschema doesn't see annotations from properties", - "data": { - "prop1": "match" - }, - "valid": false - } - ] - }, - { - "description": "naive replacement of $ref with its destination is not correct", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$defs": { - "a_string": { "type": "string" } - }, - "enum": [ - { "$ref": "#/$defs/a_string" } - ] - }, - "tests": [ - { - "description": "do not evaluate the $ref inside the enum, matching any string", - "data": "this is a string", - "valid": false - }, - { - "description": "do not evaluate the $ref inside the enum, definition exact match", - "data": { "type": "string" }, - "valid": false - }, - { - "description": "match the enum exactly", - "data": { "$ref": "#/$defs/a_string" }, - "valid": true - } - ] - }, - { - "description": "refs with relative uris and defs", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "http://example.com/schema-relative-uri-defs1.json", - "properties": { - "foo": { - "$id": "schema-relative-uri-defs2.json", - "$defs": { - "inner": { - "properties": { - "bar": { "type": "string" } - } - } - }, - "$ref": "#/$defs/inner" - } - }, - "$ref": "schema-relative-uri-defs2.json" - }, - "tests": [ - { - "description": "invalid on inner field", - "data": { - "foo": { - "bar": 1 - }, - "bar": "a" - }, - "valid": false - }, - { - "description": "invalid on outer field", - "data": { - "foo": { - "bar": "a" - }, - "bar": 1 - }, - "valid": false - }, - { - "description": "valid on both fields", - "data": { - "foo": { - "bar": "a" - }, - "bar": "a" - }, - "valid": true - } - ] - }, - { - "description": "relative refs with absolute uris and defs", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "http://example.com/schema-refs-absolute-uris-defs1.json", - "properties": { - "foo": { - "$id": "http://example.com/schema-refs-absolute-uris-defs2.json", - "$defs": { - "inner": { - "properties": { - "bar": { "type": "string" } - } - } - }, - "$ref": "#/$defs/inner" - } - }, - "$ref": "schema-refs-absolute-uris-defs2.json" - }, - "tests": [ - { - "description": "invalid on inner field", - "data": { - "foo": { - "bar": 1 - }, - "bar": "a" - }, - "valid": false - }, - { - "description": "invalid on outer field", - "data": { - "foo": { - "bar": "a" - }, - "bar": 1 - }, - "valid": false - }, - { - "description": "valid on both fields", - "data": { - "foo": { - "bar": "a" - }, - "bar": "a" - }, - "valid": true - } - ] - }, - { - "description": "$id must be resolved against nearest parent, not just immediate parent", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "http://example.com/a.json", - "$defs": { - "x": { - "$id": "http://example.com/b/c.json", - "not": { - "$defs": { - "y": { - "$id": "d.json", - "type": "number" - } - } - } - } - }, - "allOf": [ - { - "$ref": "http://example.com/b/d.json" - } - ] - }, - "tests": [ - { - "description": "number is valid", - "data": 1, - "valid": true - }, - { - "description": "non-number is invalid", - "data": "a", - "valid": false - } - ] - }, - { - "description": "order of evaluation: $id and $ref", - "schema": { - "$comment": "$id must be evaluated before $ref to get the proper $ref destination", - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://example.com/draft2020-12/ref-and-id1/base.json", - "$ref": "int.json", - "$defs": { - "bigint": { - "$comment": "canonical uri: https://example.com/ref-and-id1/int.json", - "$id": "int.json", - "maximum": 10 - }, - "smallint": { - "$comment": "canonical uri: https://example.com/ref-and-id1-int.json", - "$id": "/draft2020-12/ref-and-id1-int.json", - "maximum": 2 - } - } - }, - "tests": [ - { - "description": "data is valid against first definition", - "data": 5, - "valid": true - }, - { - "description": "data is invalid against first definition", - "data": 50, - "valid": false - } - ] - }, - { - "description": "order of evaluation: $id and $anchor and $ref", - "schema": { - "$comment": "$id must be evaluated before $ref to get the proper $ref destination", - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://example.com/draft2020-12/ref-and-id2/base.json", - "$ref": "#bigint", - "$defs": { - "bigint": { - "$comment": "canonical uri: /ref-and-id2/base.json#/$defs/bigint; another valid uri for this location: /ref-and-id2/base.json#bigint", - "$anchor": "bigint", - "maximum": 10 - }, - "smallint": { - "$comment": "canonical uri: https://example.com/ref-and-id2#/$defs/smallint; another valid uri for this location: https://example.com/ref-and-id2/#bigint", - "$id": "https://example.com/draft2020-12/ref-and-id2/", - "$anchor": "bigint", - "maximum": 2 - } - } - }, - "tests": [ - { - "description": "data is valid against first definition", - "data": 5, - "valid": true - }, - { - "description": "data is invalid against first definition", - "data": 50, - "valid": false - } - ] - }, - { - "description": "order of evaluation: $id and $ref on nested schema", - "schema": { - "$comment": "$id must be evaluated before $ref to get the proper $ref destination", - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://example.com/draft2020-12/ref-and-id3/base.json", - "$ref": "nested/foo.json", - "$defs": { - "foo": { - "$comment": "canonical uri: https://example.com/draft2020-12/ref-and-id3/nested/foo.json", - "$id": "nested/foo.json", - "$ref": "./bar.json" - }, - "bar": { - "$comment": "canonical uri: https://example.com/draft2020-12/ref-and-id3/nested/bar.json", - "$id": "nested/bar.json", - "type": "number" - } - } - }, - "tests": [ - { - "description": "data is valid against nested sibling", - "data": 5, - "valid": true - }, - { - "description": "data is invalid against nested sibling", - "data": "a", - "valid": false - } - ] - }, - { - "description": "simple URN base URI with $ref via the URN", - "schema": { - "$comment": "URIs do not have to have HTTP(s) schemes", - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed", - "minimum": 30, - "properties": { - "foo": {"$ref": "urn:uuid:deadbeef-1234-ffff-ffff-4321feebdaed"} - } - }, - "tests": [ - { - "description": "valid under the URN IDed schema", - "data": {"foo": 37}, - "valid": true - }, - { - "description": "invalid under the URN IDed schema", - "data": {"foo": 12}, - "valid": false - } - ] - }, - { - "description": "simple URN base URI with JSON pointer", - "schema": { - "$comment": "URIs do not have to have HTTP(s) schemes", - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "urn:uuid:deadbeef-1234-00ff-ff00-4321feebdaed", - "properties": { - "foo": {"$ref": "#/$defs/bar"} - }, - "$defs": { - "bar": {"type": "string"} - } - }, - "tests": [ - { - "description": "a string is valid", - "data": {"foo": "bar"}, - "valid": true - }, - { - "description": "a non-string is invalid", - "data": {"foo": 12}, - "valid": false - } - ] - }, - { - "description": "URN base URI with NSS", - "schema": { - "$comment": "RFC 8141 §2.2", - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "urn:example:1/406/47452/2", - "properties": { - "foo": {"$ref": "#/$defs/bar"} - }, - "$defs": { - "bar": {"type": "string"} - } - }, - "tests": [ - { - "description": "a string is valid", - "data": {"foo": "bar"}, - "valid": true - }, - { - "description": "a non-string is invalid", - "data": {"foo": 12}, - "valid": false - } - ] - }, - { - "description": "URN base URI with r-component", - "schema": { - "$comment": "RFC 8141 §2.3.1", - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "urn:example:foo-bar-baz-qux?+CCResolve:cc=uk", - "properties": { - "foo": {"$ref": "#/$defs/bar"} - }, - "$defs": { - "bar": {"type": "string"} - } - }, - "tests": [ - { - "description": "a string is valid", - "data": {"foo": "bar"}, - "valid": true - }, - { - "description": "a non-string is invalid", - "data": {"foo": 12}, - "valid": false - } - ] - }, - { - "description": "URN base URI with q-component", - "schema": { - "$comment": "RFC 8141 §2.3.2", - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "urn:example:weather?=op=map&lat=39.56&lon=-104.85&datetime=1969-07-21T02:56:15Z", - "properties": { - "foo": {"$ref": "#/$defs/bar"} - }, - "$defs": { - "bar": {"type": "string"} - } - }, - "tests": [ - { - "description": "a string is valid", - "data": {"foo": "bar"}, - "valid": true - }, - { - "description": "a non-string is invalid", - "data": {"foo": 12}, - "valid": false - } - ] - }, - { - "description": "URN base URI with URN and JSON pointer ref", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "urn:uuid:deadbeef-1234-0000-0000-4321feebdaed", - "properties": { - "foo": {"$ref": "urn:uuid:deadbeef-1234-0000-0000-4321feebdaed#/$defs/bar"} - }, - "$defs": { - "bar": {"type": "string"} - } - }, - "tests": [ - { - "description": "a string is valid", - "data": {"foo": "bar"}, - "valid": true - }, - { - "description": "a non-string is invalid", - "data": {"foo": 12}, - "valid": false - } - ] - }, - { - "description": "URN base URI with URN and anchor ref", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed", - "properties": { - "foo": {"$ref": "urn:uuid:deadbeef-1234-ff00-00ff-4321feebdaed#something"} - }, - "$defs": { - "bar": { - "$anchor": "something", - "type": "string" - } - } - }, - "tests": [ - { - "description": "a string is valid", - "data": {"foo": "bar"}, - "valid": true - }, - { - "description": "a non-string is invalid", - "data": {"foo": 12}, - "valid": false - } - ] - }, - { - "description": "URN ref with nested pointer ref", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$ref": "urn:uuid:deadbeef-4321-ffff-ffff-1234feebdaed", - "$defs": { - "foo": { - "$id": "urn:uuid:deadbeef-4321-ffff-ffff-1234feebdaed", - "$defs": {"bar": {"type": "string"}}, - "$ref": "#/$defs/bar" - } - } - }, - "tests": [ - { - "description": "a string is valid", - "data": "bar", - "valid": true - }, - { - "description": "a non-string is invalid", - "data": 12, - "valid": false - } - ] - }, - { - "description": "ref to if", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$ref": "http://example.com/ref/if", - "if": { - "$id": "http://example.com/ref/if", - "type": "integer" - } - }, - "tests": [ - { - "description": "a non-integer is invalid due to the $ref", - "data": "foo", - "valid": false - }, - { - "description": "an integer is valid", - "data": 12, - "valid": true - } - ] - }, - { - "description": "ref to then", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$ref": "http://example.com/ref/then", - "then": { - "$id": "http://example.com/ref/then", - "type": "integer" - } - }, - "tests": [ - { - "description": "a non-integer is invalid due to the $ref", - "data": "foo", - "valid": false - }, - { - "description": "an integer is valid", - "data": 12, - "valid": true - } - ] - }, - { - "description": "ref to else", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$ref": "http://example.com/ref/else", - "else": { - "$id": "http://example.com/ref/else", - "type": "integer" - } - }, - "tests": [ - { - "description": "a non-integer is invalid due to the $ref", - "data": "foo", - "valid": false - }, - { - "description": "an integer is valid", - "data": 12, - "valid": true - } - ] - }, - { - "description": "ref with absolute-path-reference", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "http://example.com/ref/absref.json", - "$defs": { - "a": { - "$id": "http://example.com/ref/absref/foobar.json", - "type": "number" - }, - "b": { - "$id": "http://example.com/absref/foobar.json", - "type": "string" - } - }, - "$ref": "/absref/foobar.json" - }, - "tests": [ - { - "description": "a string is valid", - "data": "foo", - "valid": true - }, - { - "description": "an integer is invalid", - "data": 12, - "valid": false - } - ] - }, - { - "description": "$id with file URI still resolves pointers - *nix", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "file:///folder/file.json", - "$defs": { - "foo": { - "type": "number" - } - }, - "$ref": "#/$defs/foo" - }, - "tests": [ - { - "description": "number is valid", - "data": 1, - "valid": true - }, - { - "description": "non-number is invalid", - "data": "a", - "valid": false - } - ] - }, - { - "description": "$id with file URI still resolves pointers - windows", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "file:///c:/folder/file.json", - "$defs": { - "foo": { - "type": "number" - } - }, - "$ref": "#/$defs/foo" - }, - "tests": [ - { - "description": "number is valid", - "data": 1, - "valid": true - }, - { - "description": "non-number is invalid", - "data": "a", - "valid": false - } - ] - }, - { - "description": "empty tokens in $ref json-pointer", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$defs": { - "": { - "$defs": { - "": { "type": "number" } - } - } - }, - "allOf": [ - { - "$ref": "#/$defs//$defs/" - } - ] - }, - "tests": [ - { - "description": "number is valid", - "data": 1, - "valid": true - }, - { - "description": "non-number is invalid", - "data": "a", - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/refRemote.json b/tests/fixtures/json-schema-test-suite/draft2020-12/refRemote.json deleted file mode 100644 index 047ac74c..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/refRemote.json +++ /dev/null @@ -1,342 +0,0 @@ -[ - { - "description": "remote ref", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$ref": "http://localhost:1234/draft2020-12/integer.json" - }, - "tests": [ - { - "description": "remote ref valid", - "data": 1, - "valid": true - }, - { - "description": "remote ref invalid", - "data": "a", - "valid": false - } - ] - }, - { - "description": "fragment within remote ref", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$ref": "http://localhost:1234/draft2020-12/subSchemas.json#/$defs/integer" - }, - "tests": [ - { - "description": "remote fragment valid", - "data": 1, - "valid": true - }, - { - "description": "remote fragment invalid", - "data": "a", - "valid": false - } - ] - }, - { - "description": "anchor within remote ref", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$ref": "http://localhost:1234/draft2020-12/locationIndependentIdentifier.json#foo" - }, - "tests": [ - { - "description": "remote anchor valid", - "data": 1, - "valid": true - }, - { - "description": "remote anchor invalid", - "data": "a", - "valid": false - } - ] - }, - { - "description": "ref within remote ref", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$ref": "http://localhost:1234/draft2020-12/subSchemas.json#/$defs/refToInteger" - }, - "tests": [ - { - "description": "ref within ref valid", - "data": 1, - "valid": true - }, - { - "description": "ref within ref invalid", - "data": "a", - "valid": false - } - ] - }, - { - "description": "base URI change", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "http://localhost:1234/draft2020-12/", - "items": { - "$id": "baseUriChange/", - "items": {"$ref": "folderInteger.json"} - } - }, - "tests": [ - { - "description": "base URI change ref valid", - "data": [[1]], - "valid": true - }, - { - "description": "base URI change ref invalid", - "data": [["a"]], - "valid": false - } - ] - }, - { - "description": "base URI change - change folder", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "http://localhost:1234/draft2020-12/scope_change_defs1.json", - "type" : "object", - "properties": {"list": {"$ref": "baseUriChangeFolder/"}}, - "$defs": { - "baz": { - "$id": "baseUriChangeFolder/", - "type": "array", - "items": {"$ref": "folderInteger.json"} - } - } - }, - "tests": [ - { - "description": "number is valid", - "data": {"list": [1]}, - "valid": true - }, - { - "description": "string is invalid", - "data": {"list": ["a"]}, - "valid": false - } - ] - }, - { - "description": "base URI change - change folder in subschema", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "http://localhost:1234/draft2020-12/scope_change_defs2.json", - "type" : "object", - "properties": {"list": {"$ref": "baseUriChangeFolderInSubschema/#/$defs/bar"}}, - "$defs": { - "baz": { - "$id": "baseUriChangeFolderInSubschema/", - "$defs": { - "bar": { - "type": "array", - "items": {"$ref": "folderInteger.json"} - } - } - } - } - }, - "tests": [ - { - "description": "number is valid", - "data": {"list": [1]}, - "valid": true - }, - { - "description": "string is invalid", - "data": {"list": ["a"]}, - "valid": false - } - ] - }, - { - "description": "root ref in remote ref", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "http://localhost:1234/draft2020-12/object", - "type": "object", - "properties": { - "name": {"$ref": "name-defs.json#/$defs/orNull"} - } - }, - "tests": [ - { - "description": "string is valid", - "data": { - "name": "foo" - }, - "valid": true - }, - { - "description": "null is valid", - "data": { - "name": null - }, - "valid": true - }, - { - "description": "object is invalid", - "data": { - "name": { - "name": null - } - }, - "valid": false - } - ] - }, - { - "description": "remote ref with ref to defs", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "http://localhost:1234/draft2020-12/schema-remote-ref-ref-defs1.json", - "$ref": "ref-and-defs.json" - }, - "tests": [ - { - "description": "invalid", - "data": { - "bar": 1 - }, - "valid": false - }, - { - "description": "valid", - "data": { - "bar": "a" - }, - "valid": true - } - ] - }, - { - "description": "Location-independent identifier in remote ref", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$ref": "http://localhost:1234/draft2020-12/locationIndependentIdentifier.json#/$defs/refToInteger" - }, - "tests": [ - { - "description": "integer is valid", - "data": 1, - "valid": true - }, - { - "description": "string is invalid", - "data": "foo", - "valid": false - } - ] - }, - { - "description": "retrieved nested refs resolve relative to their URI not $id", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "http://localhost:1234/draft2020-12/some-id", - "properties": { - "name": {"$ref": "nested/foo-ref-string.json"} - } - }, - "tests": [ - { - "description": "number is invalid", - "data": { - "name": {"foo": 1} - }, - "valid": false - }, - { - "description": "string is valid", - "data": { - "name": {"foo": "a"} - }, - "valid": true - } - ] - }, - { - "description": "remote HTTP ref with different $id", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$ref": "http://localhost:1234/different-id-ref-string.json" - }, - "tests": [ - { - "description": "number is invalid", - "data": 1, - "valid": false - }, - { - "description": "string is valid", - "data": "foo", - "valid": true - } - ] - }, - { - "description": "remote HTTP ref with different URN $id", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$ref": "http://localhost:1234/urn-ref-string.json" - }, - "tests": [ - { - "description": "number is invalid", - "data": 1, - "valid": false - }, - { - "description": "string is valid", - "data": "foo", - "valid": true - } - ] - }, - { - "description": "remote HTTP ref with nested absolute ref", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$ref": "http://localhost:1234/nested-absolute-ref-to-string.json" - }, - "tests": [ - { - "description": "number is invalid", - "data": 1, - "valid": false - }, - { - "description": "string is valid", - "data": "foo", - "valid": true - } - ] - }, - { - "description": "$ref to $ref finds detached $anchor", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$ref": "http://localhost:1234/draft2020-12/detached-ref.json#/$defs/foo" - }, - "tests": [ - { - "description": "number is valid", - "data": 1, - "valid": true - }, - { - "description": "non-number is invalid", - "data": "a", - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/required.json b/tests/fixtures/json-schema-test-suite/draft2020-12/required.json deleted file mode 100644 index b7cb99a6..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/required.json +++ /dev/null @@ -1,158 +0,0 @@ -[ - { - "description": "required validation", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": {}, - "bar": {} - }, - "required": ["foo"] - }, - "tests": [ - { - "description": "present required property is valid", - "data": {"foo": 1}, - "valid": true - }, - { - "description": "non-present required property is invalid", - "data": {"bar": 1}, - "valid": false - }, - { - "description": "ignores arrays", - "data": [], - "valid": true - }, - { - "description": "ignores strings", - "data": "", - "valid": true - }, - { - "description": "ignores other non-objects", - "data": 12, - "valid": true - } - ] - }, - { - "description": "required default validation", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": {} - } - }, - "tests": [ - { - "description": "not required by default", - "data": {}, - "valid": true - } - ] - }, - { - "description": "required with empty array", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": {} - }, - "required": [] - }, - "tests": [ - { - "description": "property not required", - "data": {}, - "valid": true - } - ] - }, - { - "description": "required with escaped characters", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "required": [ - "foo\nbar", - "foo\"bar", - "foo\\bar", - "foo\rbar", - "foo\tbar", - "foo\fbar" - ] - }, - "tests": [ - { - "description": "object with all properties present is valid", - "data": { - "foo\nbar": 1, - "foo\"bar": 1, - "foo\\bar": 1, - "foo\rbar": 1, - "foo\tbar": 1, - "foo\fbar": 1 - }, - "valid": true - }, - { - "description": "object with some properties missing is invalid", - "data": { - "foo\nbar": "1", - "foo\"bar": "1" - }, - "valid": false - } - ] - }, - { - "description": "required properties whose names are Javascript object property names", - "comment": "Ensure JS implementations don't universally consider e.g. __proto__ to always be present in an object.", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "required": ["__proto__", "toString", "constructor"] - }, - "tests": [ - { - "description": "ignores arrays", - "data": [], - "valid": true - }, - { - "description": "ignores other non-objects", - "data": 12, - "valid": true - }, - { - "description": "none of the properties mentioned", - "data": {}, - "valid": false - }, - { - "description": "__proto__ present", - "data": { "__proto__": "foo" }, - "valid": false - }, - { - "description": "toString present", - "data": { "toString": { "length": 37 } }, - "valid": false - }, - { - "description": "constructor present", - "data": { "constructor": { "length": 37 } }, - "valid": false - }, - { - "description": "all present", - "data": { - "__proto__": 12, - "toString": { "length": "foo" }, - "constructor": 37 - }, - "valid": true - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/type.json b/tests/fixtures/json-schema-test-suite/draft2020-12/type.json deleted file mode 100644 index 2123c408..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/type.json +++ /dev/null @@ -1,501 +0,0 @@ -[ - { - "description": "integer type matches integers", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "integer" - }, - "tests": [ - { - "description": "an integer is an integer", - "data": 1, - "valid": true - }, - { - "description": "a float with zero fractional part is an integer", - "data": 1.0, - "valid": true - }, - { - "description": "a float is not an integer", - "data": 1.1, - "valid": false - }, - { - "description": "a string is not an integer", - "data": "foo", - "valid": false - }, - { - "description": "a string is still not an integer, even if it looks like one", - "data": "1", - "valid": false - }, - { - "description": "an object is not an integer", - "data": {}, - "valid": false - }, - { - "description": "an array is not an integer", - "data": [], - "valid": false - }, - { - "description": "a boolean is not an integer", - "data": true, - "valid": false - }, - { - "description": "null is not an integer", - "data": null, - "valid": false - } - ] - }, - { - "description": "number type matches numbers", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "number" - }, - "tests": [ - { - "description": "an integer is a number", - "data": 1, - "valid": true - }, - { - "description": "a float with zero fractional part is a number (and an integer)", - "data": 1.0, - "valid": true - }, - { - "description": "a float is a number", - "data": 1.1, - "valid": true - }, - { - "description": "a string is not a number", - "data": "foo", - "valid": false - }, - { - "description": "a string is still not a number, even if it looks like one", - "data": "1", - "valid": false - }, - { - "description": "an object is not a number", - "data": {}, - "valid": false - }, - { - "description": "an array is not a number", - "data": [], - "valid": false - }, - { - "description": "a boolean is not a number", - "data": true, - "valid": false - }, - { - "description": "null is not a number", - "data": null, - "valid": false - } - ] - }, - { - "description": "string type matches strings", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "string" - }, - "tests": [ - { - "description": "1 is not a string", - "data": 1, - "valid": false - }, - { - "description": "a float is not a string", - "data": 1.1, - "valid": false - }, - { - "description": "a string is a string", - "data": "foo", - "valid": true - }, - { - "description": "a string is still a string, even if it looks like a number", - "data": "1", - "valid": true - }, - { - "description": "an empty string is still a string", - "data": "", - "valid": true - }, - { - "description": "an object is not a string", - "data": {}, - "valid": false - }, - { - "description": "an array is not a string", - "data": [], - "valid": false - }, - { - "description": "a boolean is not a string", - "data": true, - "valid": false - }, - { - "description": "null is not a string", - "data": null, - "valid": false - } - ] - }, - { - "description": "object type matches objects", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "object" - }, - "tests": [ - { - "description": "an integer is not an object", - "data": 1, - "valid": false - }, - { - "description": "a float is not an object", - "data": 1.1, - "valid": false - }, - { - "description": "a string is not an object", - "data": "foo", - "valid": false - }, - { - "description": "an object is an object", - "data": {}, - "valid": true - }, - { - "description": "an array is not an object", - "data": [], - "valid": false - }, - { - "description": "a boolean is not an object", - "data": true, - "valid": false - }, - { - "description": "null is not an object", - "data": null, - "valid": false - } - ] - }, - { - "description": "array type matches arrays", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "array" - }, - "tests": [ - { - "description": "an integer is not an array", - "data": 1, - "valid": false - }, - { - "description": "a float is not an array", - "data": 1.1, - "valid": false - }, - { - "description": "a string is not an array", - "data": "foo", - "valid": false - }, - { - "description": "an object is not an array", - "data": {}, - "valid": false - }, - { - "description": "an array is an array", - "data": [], - "valid": true - }, - { - "description": "a boolean is not an array", - "data": true, - "valid": false - }, - { - "description": "null is not an array", - "data": null, - "valid": false - } - ] - }, - { - "description": "boolean type matches booleans", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "boolean" - }, - "tests": [ - { - "description": "an integer is not a boolean", - "data": 1, - "valid": false - }, - { - "description": "zero is not a boolean", - "data": 0, - "valid": false - }, - { - "description": "a float is not a boolean", - "data": 1.1, - "valid": false - }, - { - "description": "a string is not a boolean", - "data": "foo", - "valid": false - }, - { - "description": "an empty string is not a boolean", - "data": "", - "valid": false - }, - { - "description": "an object is not a boolean", - "data": {}, - "valid": false - }, - { - "description": "an array is not a boolean", - "data": [], - "valid": false - }, - { - "description": "true is a boolean", - "data": true, - "valid": true - }, - { - "description": "false is a boolean", - "data": false, - "valid": true - }, - { - "description": "null is not a boolean", - "data": null, - "valid": false - } - ] - }, - { - "description": "null type matches only the null object", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": "null" - }, - "tests": [ - { - "description": "an integer is not null", - "data": 1, - "valid": false - }, - { - "description": "a float is not null", - "data": 1.1, - "valid": false - }, - { - "description": "zero is not null", - "data": 0, - "valid": false - }, - { - "description": "a string is not null", - "data": "foo", - "valid": false - }, - { - "description": "an empty string is not null", - "data": "", - "valid": false - }, - { - "description": "an object is not null", - "data": {}, - "valid": false - }, - { - "description": "an array is not null", - "data": [], - "valid": false - }, - { - "description": "true is not null", - "data": true, - "valid": false - }, - { - "description": "false is not null", - "data": false, - "valid": false - }, - { - "description": "null is null", - "data": null, - "valid": true - } - ] - }, - { - "description": "multiple types can be specified in an array", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": ["integer", "string"] - }, - "tests": [ - { - "description": "an integer is valid", - "data": 1, - "valid": true - }, - { - "description": "a string is valid", - "data": "foo", - "valid": true - }, - { - "description": "a float is invalid", - "data": 1.1, - "valid": false - }, - { - "description": "an object is invalid", - "data": {}, - "valid": false - }, - { - "description": "an array is invalid", - "data": [], - "valid": false - }, - { - "description": "a boolean is invalid", - "data": true, - "valid": false - }, - { - "description": "null is invalid", - "data": null, - "valid": false - } - ] - }, - { - "description": "type as array with one item", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": ["string"] - }, - "tests": [ - { - "description": "string is valid", - "data": "foo", - "valid": true - }, - { - "description": "number is invalid", - "data": 123, - "valid": false - } - ] - }, - { - "description": "type: array or object", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": ["array", "object"] - }, - "tests": [ - { - "description": "array is valid", - "data": [1,2,3], - "valid": true - }, - { - "description": "object is valid", - "data": {"foo": 123}, - "valid": true - }, - { - "description": "number is invalid", - "data": 123, - "valid": false - }, - { - "description": "string is invalid", - "data": "foo", - "valid": false - }, - { - "description": "null is invalid", - "data": null, - "valid": false - } - ] - }, - { - "description": "type: array, object or null", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "type": ["array", "object", "null"] - }, - "tests": [ - { - "description": "array is valid", - "data": [1,2,3], - "valid": true - }, - { - "description": "object is valid", - "data": {"foo": 123}, - "valid": true - }, - { - "description": "null is valid", - "data": null, - "valid": true - }, - { - "description": "number is invalid", - "data": 123, - "valid": false - }, - { - "description": "string is invalid", - "data": "foo", - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/unevaluatedItems.json b/tests/fixtures/json-schema-test-suite/draft2020-12/unevaluatedItems.json deleted file mode 100644 index d8a7c1b5..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/unevaluatedItems.json +++ /dev/null @@ -1,854 +0,0 @@ -[ - { - "description": "unevaluatedItems true", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "unevaluatedItems": true - }, - "tests": [ - { - "description": "with no unevaluated items", - "data": [], - "valid": true - }, - { - "description": "with unevaluated items", - "data": ["foo"], - "valid": true - } - ] - }, - { - "description": "unevaluatedItems false", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "unevaluatedItems": false - }, - "tests": [ - { - "description": "with no unevaluated items", - "data": [], - "valid": true - }, - { - "description": "with unevaluated items", - "data": ["foo"], - "valid": false - } - ] - }, - { - "description": "unevaluatedItems as schema", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "unevaluatedItems": { "type": "string" } - }, - "tests": [ - { - "description": "with no unevaluated items", - "data": [], - "valid": true - }, - { - "description": "with valid unevaluated items", - "data": ["foo"], - "valid": true - }, - { - "description": "with invalid unevaluated items", - "data": [42], - "valid": false - } - ] - }, - { - "description": "unevaluatedItems with uniform items", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "items": { "type": "string" }, - "unevaluatedItems": false - }, - "tests": [ - { - "description": "unevaluatedItems doesn't apply", - "data": ["foo", "bar"], - "valid": true - } - ] - }, - { - "description": "unevaluatedItems with tuple", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "prefixItems": [ - { "type": "string" } - ], - "unevaluatedItems": false - }, - "tests": [ - { - "description": "with no unevaluated items", - "data": ["foo"], - "valid": true - }, - { - "description": "with unevaluated items", - "data": ["foo", "bar"], - "valid": false - } - ] - }, - { - "description": "unevaluatedItems with items and prefixItems", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "prefixItems": [ - { "type": "string" } - ], - "items": true, - "unevaluatedItems": false - }, - "tests": [ - { - "description": "unevaluatedItems doesn't apply", - "data": ["foo", 42], - "valid": true - } - ] - }, - { - "description": "unevaluatedItems with items", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "items": {"type": "number"}, - "unevaluatedItems": {"type": "string"} - }, - "tests": [ - { - "description": "valid under items", - "comment": "no elements are considered by unevaluatedItems", - "data": [5, 6, 7, 8], - "valid": true - }, - { - "description": "invalid under items", - "data": ["foo", "bar", "baz"], - "valid": false - } - ] - }, - { - "description": "unevaluatedItems with nested tuple", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "prefixItems": [ - { "type": "string" } - ], - "allOf": [ - { - "prefixItems": [ - true, - { "type": "number" } - ] - } - ], - "unevaluatedItems": false - }, - "tests": [ - { - "description": "with no unevaluated items", - "data": ["foo", 42], - "valid": true - }, - { - "description": "with unevaluated items", - "data": ["foo", 42, true], - "valid": false - } - ] - }, - { - "description": "unevaluatedItems with nested items", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "unevaluatedItems": {"type": "boolean"}, - "anyOf": [ - { "items": {"type": "string"} }, - true - ] - }, - "tests": [ - { - "description": "with only (valid) additional items", - "data": [true, false], - "valid": true - }, - { - "description": "with no additional items", - "data": ["yes", "no"], - "valid": true - }, - { - "description": "with invalid additional item", - "data": ["yes", false], - "valid": false - } - ] - }, - { - "description": "unevaluatedItems with nested prefixItems and items", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [ - { - "prefixItems": [ - { "type": "string" } - ], - "items": true - } - ], - "unevaluatedItems": false - }, - "tests": [ - { - "description": "with no additional items", - "data": ["foo"], - "valid": true - }, - { - "description": "with additional items", - "data": ["foo", 42, true], - "valid": true - } - ] - }, - { - "description": "unevaluatedItems with nested unevaluatedItems", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [ - { - "prefixItems": [ - { "type": "string" } - ] - }, - { "unevaluatedItems": true } - ], - "unevaluatedItems": false - }, - "tests": [ - { - "description": "with no additional items", - "data": ["foo"], - "valid": true - }, - { - "description": "with additional items", - "data": ["foo", 42, true], - "valid": true - } - ] - }, - { - "description": "unevaluatedItems with anyOf", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "prefixItems": [ - { "const": "foo" } - ], - "anyOf": [ - { - "prefixItems": [ - true, - { "const": "bar" } - ] - }, - { - "prefixItems": [ - true, - true, - { "const": "baz" } - ] - } - ], - "unevaluatedItems": false - }, - "tests": [ - { - "description": "when one schema matches and has no unevaluated items", - "data": ["foo", "bar"], - "valid": true - }, - { - "description": "when one schema matches and has unevaluated items", - "data": ["foo", "bar", 42], - "valid": false - }, - { - "description": "when two schemas match and has no unevaluated items", - "data": ["foo", "bar", "baz"], - "valid": true - }, - { - "description": "when two schemas match and has unevaluated items", - "data": ["foo", "bar", "baz", 42], - "valid": false - } - ] - }, - { - "description": "unevaluatedItems with oneOf", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "prefixItems": [ - { "const": "foo" } - ], - "oneOf": [ - { - "prefixItems": [ - true, - { "const": "bar" } - ] - }, - { - "prefixItems": [ - true, - { "const": "baz" } - ] - } - ], - "unevaluatedItems": false - }, - "tests": [ - { - "description": "with no unevaluated items", - "data": ["foo", "bar"], - "valid": true - }, - { - "description": "with unevaluated items", - "data": ["foo", "bar", 42], - "valid": false - } - ] - }, - { - "description": "unevaluatedItems with not", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "prefixItems": [ - { "const": "foo" } - ], - "not": { - "not": { - "prefixItems": [ - true, - { "const": "bar" } - ] - } - }, - "unevaluatedItems": false - }, - "tests": [ - { - "description": "with unevaluated items", - "data": ["foo", "bar"], - "valid": false - } - ] - }, - { - "description": "unevaluatedItems with if/then/else", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "prefixItems": [ - { "const": "foo" } - ], - "if": { - "prefixItems": [ - true, - { "const": "bar" } - ] - }, - "then": { - "prefixItems": [ - true, - true, - { "const": "then" } - ] - }, - "else": { - "prefixItems": [ - true, - true, - true, - { "const": "else" } - ] - }, - "unevaluatedItems": false - }, - "tests": [ - { - "description": "when if matches and it has no unevaluated items", - "data": ["foo", "bar", "then"], - "valid": true - }, - { - "description": "when if matches and it has unevaluated items", - "data": ["foo", "bar", "then", "else"], - "valid": false - }, - { - "description": "when if doesn't match and it has no unevaluated items", - "data": ["foo", 42, 42, "else"], - "valid": true - }, - { - "description": "when if doesn't match and it has unevaluated items", - "data": ["foo", 42, 42, "else", 42], - "valid": false - } - ] - }, - { - "description": "unevaluatedItems with boolean schemas", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [true], - "unevaluatedItems": false - }, - "tests": [ - { - "description": "with no unevaluated items", - "data": [], - "valid": true - }, - { - "description": "with unevaluated items", - "data": ["foo"], - "valid": false - } - ] - }, - { - "description": "unevaluatedItems with $ref", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$ref": "#/$defs/bar", - "prefixItems": [ - { "type": "string" } - ], - "unevaluatedItems": false, - "$defs": { - "bar": { - "prefixItems": [ - true, - { "type": "string" } - ] - } - } - }, - "tests": [ - { - "description": "with no unevaluated items", - "data": ["foo", "bar"], - "valid": true - }, - { - "description": "with unevaluated items", - "data": ["foo", "bar", "baz"], - "valid": false - } - ] - }, - { - "description": "unevaluatedItems before $ref", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "unevaluatedItems": false, - "prefixItems": [ - { "type": "string" } - ], - "$ref": "#/$defs/bar", - "$defs": { - "bar": { - "prefixItems": [ - true, - { "type": "string" } - ] - } - } - }, - "tests": [ - { - "description": "with no unevaluated items", - "data": ["foo", "bar"], - "valid": true - }, - { - "description": "with unevaluated items", - "data": ["foo", "bar", "baz"], - "valid": false - } - ] - }, - { - "description": "unevaluatedItems with $dynamicRef", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://example.com/unevaluated-items-with-dynamic-ref/derived", - - "$ref": "./baseSchema", - - "$defs": { - "derived": { - "$dynamicAnchor": "addons", - "prefixItems": [ - true, - { "type": "string" } - ] - }, - "baseSchema": { - "$id": "./baseSchema", - - "$comment": "unevaluatedItems comes first so it's more likely to catch bugs with implementations that are sensitive to keyword ordering", - "unevaluatedItems": false, - "type": "array", - "prefixItems": [ - { "type": "string" } - ], - "$dynamicRef": "#addons", - - "$defs": { - "defaultAddons": { - "$comment": "Needed to satisfy the bookending requirement", - "$dynamicAnchor": "addons" - } - } - } - } - }, - "tests": [ - { - "description": "with no unevaluated items", - "data": ["foo", "bar"], - "valid": true - }, - { - "description": "with unevaluated items", - "data": ["foo", "bar", "baz"], - "valid": false - } - ] - }, - { - "description": "unevaluatedItems can't see inside cousins", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [ - { - "prefixItems": [ true ] - }, - { "unevaluatedItems": false } - ] - }, - "tests": [ - { - "description": "always fails", - "data": [ 1 ], - "valid": false - } - ] - }, - { - "description": "item is evaluated in an uncle schema to unevaluatedItems", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": { - "prefixItems": [ - { "type": "string" } - ], - "unevaluatedItems": false - } - }, - "anyOf": [ - { - "properties": { - "foo": { - "prefixItems": [ - true, - { "type": "string" } - ] - } - } - } - ] - }, - "tests": [ - { - "description": "no extra items", - "data": { - "foo": [ - "test" - ] - }, - "valid": true - }, - { - "description": "uncle keyword evaluation is not significant", - "data": { - "foo": [ - "test", - "test" - ] - }, - "valid": false - } - ] - }, - { - "description": "unevaluatedItems depends on adjacent contains", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "prefixItems": [true], - "contains": {"type": "string"}, - "unevaluatedItems": false - }, - "tests": [ - { - "description": "second item is evaluated by contains", - "data": [ 1, "foo" ], - "valid": true - }, - { - "description": "contains fails, second item is not evaluated", - "data": [ 1, 2 ], - "valid": false - }, - { - "description": "contains passes, second item is not evaluated", - "data": [ 1, 2, "foo" ], - "valid": false - } - ] - }, - { - "description": "unevaluatedItems depends on multiple nested contains", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [ - { "contains": { "multipleOf": 2 } }, - { "contains": { "multipleOf": 3 } } - ], - "unevaluatedItems": { "multipleOf": 5 } - }, - "tests": [ - { - "description": "5 not evaluated, passes unevaluatedItems", - "data": [ 2, 3, 4, 5, 6 ], - "valid": true - }, - { - "description": "7 not evaluated, fails unevaluatedItems", - "data": [ 2, 3, 4, 7, 8 ], - "valid": false - } - ] - }, - { - "description": "unevaluatedItems and contains interact to control item dependency relationship", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "if": { - "contains": {"const": "a"} - }, - "then": { - "if": { - "contains": {"const": "b"} - }, - "then": { - "if": { - "contains": {"const": "c"} - } - } - }, - "unevaluatedItems": false - }, - "tests": [ - { - "description": "empty array is valid", - "data": [], - "valid": true - }, - { - "description": "only a's are valid", - "data": [ "a", "a" ], - "valid": true - }, - { - "description": "a's and b's are valid", - "data": [ "a", "b", "a", "b", "a" ], - "valid": true - }, - { - "description": "a's, b's and c's are valid", - "data": [ "c", "a", "c", "c", "b", "a" ], - "valid": true - }, - { - "description": "only b's are invalid", - "data": [ "b", "b" ], - "valid": false - }, - { - "description": "only c's are invalid", - "data": [ "c", "c" ], - "valid": false - }, - { - "description": "only b's and c's are invalid", - "data": [ "c", "b", "c", "b", "c" ], - "valid": false - }, - { - "description": "only a's and c's are invalid", - "data": [ "c", "a", "c", "a", "c" ], - "valid": false - } - ] - }, - { - "description" : "unevaluatedItems with minContains = 0", - "schema" : { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "contains": {"type": "string"}, - "minContains": 0, - "unevaluatedItems": false - }, - "tests" : [ - { - "description": "empty array is valid", - "data": [], - "valid": true - }, - { - "description": "no items evaluated by contains", - "data": [0], - "valid": false - }, - { - "description": "some but not all items evaluated by contains", - "data": ["foo", 0], - "valid": false - }, - { - "description": "all items evaluated by contains", - "data": ["foo", "bar"], - "valid": true - } - ] - }, - { - "description": "non-array instances are valid", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "unevaluatedItems": false - }, - "tests": [ - { - "description": "ignores booleans", - "data": true, - "valid": true - }, - { - "description": "ignores integers", - "data": 123, - "valid": true - }, - { - "description": "ignores floats", - "data": 1.0, - "valid": true - }, - { - "description": "ignores objects", - "data": {}, - "valid": true - }, - { - "description": "ignores strings", - "data": "foo", - "valid": true - }, - { - "description": "ignores null", - "data": null, - "valid": true - } - ] - }, - { - "description": "unevaluatedItems with null instance elements", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "unevaluatedItems": { - "type": "null" - } - }, - "tests": [ - { - "description": "allows null elements", - "data": [ null ], - "valid": true - } - ] - }, - { - "description": "unevaluatedItems can see annotations from if without then and else", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "if": { - "prefixItems": [{"const": "a"}] - }, - "unevaluatedItems": false - }, - "tests": [ - { - "description": "valid in case if is evaluated", - "data": [ "a" ], - "valid": true - }, - { - "description": "invalid in case if is evaluated", - "data": [ "b" ], - "valid": false - } - ] - }, - { - "description": "Evaluated items collection needs to consider instance location", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "prefixItems": [ - { - "prefixItems": [ - true, - { "type": "string" } - ] - } - ], - "unevaluatedItems": false - }, - "tests": [ - { - "description": "with an unevaluated item that exists at another location", - "data": [ - ["foo", "bar"], - "bar" - ], - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/unevaluatedProperties.json b/tests/fixtures/json-schema-test-suite/draft2020-12/unevaluatedProperties.json deleted file mode 100644 index 9c18b9ef..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/unevaluatedProperties.json +++ /dev/null @@ -1,1613 +0,0 @@ -[ - { - "description": "unevaluatedProperties true", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "unevaluatedProperties": true - }, - "tests": [ - { - "description": "with no unevaluated properties", - "data": {}, - "valid": true - }, - { - "description": "with unevaluated properties", - "data": { - "foo": "foo" - }, - "valid": true - } - ] - }, - { - "description": "unevaluatedProperties schema", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "unevaluatedProperties": { - "type": "string", - "minLength": 3 - } - }, - "tests": [ - { - "description": "with no unevaluated properties", - "data": {}, - "valid": true - }, - { - "description": "with valid unevaluated properties", - "data": { - "foo": "foo" - }, - "valid": true - }, - { - "description": "with invalid unevaluated properties", - "data": { - "foo": "fo" - }, - "valid": false - } - ] - }, - { - "description": "unevaluatedProperties false", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "unevaluatedProperties": false - }, - "tests": [ - { - "description": "with no unevaluated properties", - "data": {}, - "valid": true - }, - { - "description": "with unevaluated properties", - "data": { - "foo": "foo" - }, - "valid": false - } - ] - }, - { - "description": "unevaluatedProperties with adjacent properties", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": { "type": "string" } - }, - "unevaluatedProperties": false - }, - "tests": [ - { - "description": "with no unevaluated properties", - "data": { - "foo": "foo" - }, - "valid": true - }, - { - "description": "with unevaluated properties", - "data": { - "foo": "foo", - "bar": "bar" - }, - "valid": false - } - ] - }, - { - "description": "unevaluatedProperties with adjacent patternProperties", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "patternProperties": { - "^foo": { "type": "string" } - }, - "unevaluatedProperties": false - }, - "tests": [ - { - "description": "with no unevaluated properties", - "data": { - "foo": "foo" - }, - "valid": true - }, - { - "description": "with unevaluated properties", - "data": { - "foo": "foo", - "bar": "bar" - }, - "valid": false - } - ] - }, - { - "description": "unevaluatedProperties with adjacent bool additionalProperties", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "additionalProperties": true, - "unevaluatedProperties": false - }, - "tests": [ - { - "description": "with no additional properties", - "data": { - "foo": "foo" - }, - "valid": true - }, - { - "description": "with additional properties", - "data": { - "foo": "foo", - "bar": "bar" - }, - "valid": true - } - ] - }, - { - "description": "unevaluatedProperties with adjacent non-bool additionalProperties", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "additionalProperties": { "type": "string" }, - "unevaluatedProperties": false - }, - "tests": [ - { - "description": "with only valid additional properties", - "data": { - "foo": "foo" - }, - "valid": true - }, - { - "description": "with invalid additional properties", - "data": { - "foo": "foo", - "bar": 1 - }, - "valid": false - } - ] - }, - { - "description": "unevaluatedProperties with nested properties", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": { "type": "string" } - }, - "allOf": [ - { - "properties": { - "bar": { "type": "string" } - } - } - ], - "unevaluatedProperties": false - }, - "tests": [ - { - "description": "with no additional properties", - "data": { - "foo": "foo", - "bar": "bar" - }, - "valid": true - }, - { - "description": "with additional properties", - "data": { - "foo": "foo", - "bar": "bar", - "baz": "baz" - }, - "valid": false - } - ] - }, - { - "description": "unevaluatedProperties with nested patternProperties", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": { "type": "string" } - }, - "allOf": [ - { - "patternProperties": { - "^bar": { "type": "string" } - } - } - ], - "unevaluatedProperties": false - }, - "tests": [ - { - "description": "with no additional properties", - "data": { - "foo": "foo", - "bar": "bar" - }, - "valid": true - }, - { - "description": "with additional properties", - "data": { - "foo": "foo", - "bar": "bar", - "baz": "baz" - }, - "valid": false - } - ] - }, - { - "description": "unevaluatedProperties with nested additionalProperties", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": { "type": "string" } - }, - "allOf": [ - { - "additionalProperties": true - } - ], - "unevaluatedProperties": false - }, - "tests": [ - { - "description": "with no additional properties", - "data": { - "foo": "foo" - }, - "valid": true - }, - { - "description": "with additional properties", - "data": { - "foo": "foo", - "bar": "bar" - }, - "valid": true - } - ] - }, - { - "description": "unevaluatedProperties with nested unevaluatedProperties", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": { "type": "string" } - }, - "allOf": [ - { - "unevaluatedProperties": true - } - ], - "unevaluatedProperties": { - "type": "string", - "maxLength": 2 - } - }, - "tests": [ - { - "description": "with no nested unevaluated properties", - "data": { - "foo": "foo" - }, - "valid": true - }, - { - "description": "with nested unevaluated properties", - "data": { - "foo": "foo", - "bar": "bar" - }, - "valid": true - } - ] - }, - { - "description": "unevaluatedProperties with anyOf", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": { "type": "string" } - }, - "anyOf": [ - { - "properties": { - "bar": { "const": "bar" } - }, - "required": ["bar"] - }, - { - "properties": { - "baz": { "const": "baz" } - }, - "required": ["baz"] - }, - { - "properties": { - "quux": { "const": "quux" } - }, - "required": ["quux"] - } - ], - "unevaluatedProperties": false - }, - "tests": [ - { - "description": "when one matches and has no unevaluated properties", - "data": { - "foo": "foo", - "bar": "bar" - }, - "valid": true - }, - { - "description": "when one matches and has unevaluated properties", - "data": { - "foo": "foo", - "bar": "bar", - "baz": "not-baz" - }, - "valid": false - }, - { - "description": "when two match and has no unevaluated properties", - "data": { - "foo": "foo", - "bar": "bar", - "baz": "baz" - }, - "valid": true - }, - { - "description": "when two match and has unevaluated properties", - "data": { - "foo": "foo", - "bar": "bar", - "baz": "baz", - "quux": "not-quux" - }, - "valid": false - } - ] - }, - { - "description": "unevaluatedProperties with oneOf", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": { "type": "string" } - }, - "oneOf": [ - { - "properties": { - "bar": { "const": "bar" } - }, - "required": ["bar"] - }, - { - "properties": { - "baz": { "const": "baz" } - }, - "required": ["baz"] - } - ], - "unevaluatedProperties": false - }, - "tests": [ - { - "description": "with no unevaluated properties", - "data": { - "foo": "foo", - "bar": "bar" - }, - "valid": true - }, - { - "description": "with unevaluated properties", - "data": { - "foo": "foo", - "bar": "bar", - "quux": "quux" - }, - "valid": false - } - ] - }, - { - "description": "unevaluatedProperties with not", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": { "type": "string" } - }, - "not": { - "not": { - "properties": { - "bar": { "const": "bar" } - }, - "required": ["bar"] - } - }, - "unevaluatedProperties": false - }, - "tests": [ - { - "description": "with unevaluated properties", - "data": { - "foo": "foo", - "bar": "bar" - }, - "valid": false - } - ] - }, - { - "description": "unevaluatedProperties with if/then/else", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "if": { - "properties": { - "foo": { "const": "then" } - }, - "required": ["foo"] - }, - "then": { - "properties": { - "bar": { "type": "string" } - }, - "required": ["bar"] - }, - "else": { - "properties": { - "baz": { "type": "string" } - }, - "required": ["baz"] - }, - "unevaluatedProperties": false - }, - "tests": [ - { - "description": "when if is true and has no unevaluated properties", - "data": { - "foo": "then", - "bar": "bar" - }, - "valid": true - }, - { - "description": "when if is true and has unevaluated properties", - "data": { - "foo": "then", - "bar": "bar", - "baz": "baz" - }, - "valid": false - }, - { - "description": "when if is false and has no unevaluated properties", - "data": { - "baz": "baz" - }, - "valid": true - }, - { - "description": "when if is false and has unevaluated properties", - "data": { - "foo": "else", - "baz": "baz" - }, - "valid": false - } - ] - }, - { - "description": "unevaluatedProperties with if/then/else, then not defined", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "if": { - "properties": { - "foo": { "const": "then" } - }, - "required": ["foo"] - }, - "else": { - "properties": { - "baz": { "type": "string" } - }, - "required": ["baz"] - }, - "unevaluatedProperties": false - }, - "tests": [ - { - "description": "when if is true and has no unevaluated properties", - "data": { - "foo": "then" - }, - "valid": true - }, - { - "description": "when if is true and has unevaluated properties", - "data": { - "foo": "then", - "bar": "bar" - }, - "valid": false - }, - { - "description": "when if is false and has no unevaluated properties", - "data": { - "baz": "baz" - }, - "valid": true - }, - { - "description": "when if is false and has unevaluated properties", - "data": { - "foo": "else", - "baz": "baz" - }, - "valid": false - } - ] - }, - { - "description": "unevaluatedProperties with if/then/else, else not defined", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "if": { - "properties": { - "foo": { "const": "then" } - }, - "required": ["foo"] - }, - "then": { - "properties": { - "bar": { "type": "string" } - }, - "required": ["bar"] - }, - "unevaluatedProperties": false - }, - "tests": [ - { - "description": "when if is true and has no unevaluated properties", - "data": { - "foo": "then", - "bar": "bar" - }, - "valid": true - }, - { - "description": "when if is true and has unevaluated properties", - "data": { - "foo": "then", - "bar": "bar", - "baz": "baz" - }, - "valid": false - }, - { - "description": "when if is false and has no unevaluated properties", - "data": { - "baz": "baz" - }, - "valid": false - }, - { - "description": "when if is false and has unevaluated properties", - "data": { - "foo": "else", - "baz": "baz" - }, - "valid": false - } - ] - }, - { - "description": "unevaluatedProperties with dependentSchemas", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": { "type": "string" } - }, - "dependentSchemas": { - "foo": { - "properties": { - "bar": { "const": "bar" } - }, - "required": ["bar"] - } - }, - "unevaluatedProperties": false - }, - "tests": [ - { - "description": "with no unevaluated properties", - "data": { - "foo": "foo", - "bar": "bar" - }, - "valid": true - }, - { - "description": "with unevaluated properties", - "data": { - "bar": "bar" - }, - "valid": false - } - ] - }, - { - "description": "unevaluatedProperties with boolean schemas", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": { "type": "string" } - }, - "allOf": [true], - "unevaluatedProperties": false - }, - "tests": [ - { - "description": "with no unevaluated properties", - "data": { - "foo": "foo" - }, - "valid": true - }, - { - "description": "with unevaluated properties", - "data": { - "bar": "bar" - }, - "valid": false - } - ] - }, - { - "description": "unevaluatedProperties with $ref", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$ref": "#/$defs/bar", - "properties": { - "foo": { "type": "string" } - }, - "unevaluatedProperties": false, - "$defs": { - "bar": { - "properties": { - "bar": { "type": "string" } - } - } - } - }, - "tests": [ - { - "description": "with no unevaluated properties", - "data": { - "foo": "foo", - "bar": "bar" - }, - "valid": true - }, - { - "description": "with unevaluated properties", - "data": { - "foo": "foo", - "bar": "bar", - "baz": "baz" - }, - "valid": false - } - ] - }, - { - "description": "unevaluatedProperties before $ref", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "unevaluatedProperties": false, - "properties": { - "foo": { "type": "string" } - }, - "$ref": "#/$defs/bar", - "$defs": { - "bar": { - "properties": { - "bar": { "type": "string" } - } - } - } - }, - "tests": [ - { - "description": "with no unevaluated properties", - "data": { - "foo": "foo", - "bar": "bar" - }, - "valid": true - }, - { - "description": "with unevaluated properties", - "data": { - "foo": "foo", - "bar": "bar", - "baz": "baz" - }, - "valid": false - } - ] - }, - { - "description": "unevaluatedProperties with $dynamicRef", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://example.com/unevaluated-properties-with-dynamic-ref/derived", - - "$ref": "./baseSchema", - - "$defs": { - "derived": { - "$dynamicAnchor": "addons", - "properties": { - "bar": { "type": "string" } - } - }, - "baseSchema": { - "$id": "./baseSchema", - - "$comment": "unevaluatedProperties comes first so it's more likely to catch bugs with implementations that are sensitive to keyword ordering", - "unevaluatedProperties": false, - "properties": { - "foo": { "type": "string" } - }, - "$dynamicRef": "#addons", - - "$defs": { - "defaultAddons": { - "$comment": "Needed to satisfy the bookending requirement", - "$dynamicAnchor": "addons" - } - } - } - } - }, - "tests": [ - { - "description": "with no unevaluated properties", - "data": { - "foo": "foo", - "bar": "bar" - }, - "valid": true - }, - { - "description": "with unevaluated properties", - "data": { - "foo": "foo", - "bar": "bar", - "baz": "baz" - }, - "valid": false - } - ] - }, - { - "description": "unevaluatedProperties can't see inside cousins", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [ - { - "properties": { - "foo": true - } - }, - { - "unevaluatedProperties": false - } - ] - }, - "tests": [ - { - "description": "always fails", - "data": { - "foo": 1 - }, - "valid": false - } - ] - }, - { - "description": "unevaluatedProperties can't see inside cousins (reverse order)", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [ - { - "unevaluatedProperties": false - }, - { - "properties": { - "foo": true - } - } - ] - }, - "tests": [ - { - "description": "always fails", - "data": { - "foo": 1 - }, - "valid": false - } - ] - }, - { - "description": "nested unevaluatedProperties, outer false, inner true, properties outside", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": { "type": "string" } - }, - "allOf": [ - { - "unevaluatedProperties": true - } - ], - "unevaluatedProperties": false - }, - "tests": [ - { - "description": "with no nested unevaluated properties", - "data": { - "foo": "foo" - }, - "valid": true - }, - { - "description": "with nested unevaluated properties", - "data": { - "foo": "foo", - "bar": "bar" - }, - "valid": true - } - ] - }, - { - "description": "nested unevaluatedProperties, outer false, inner true, properties inside", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [ - { - "properties": { - "foo": { "type": "string" } - }, - "unevaluatedProperties": true - } - ], - "unevaluatedProperties": false - }, - "tests": [ - { - "description": "with no nested unevaluated properties", - "data": { - "foo": "foo" - }, - "valid": true - }, - { - "description": "with nested unevaluated properties", - "data": { - "foo": "foo", - "bar": "bar" - }, - "valid": true - } - ] - }, - { - "description": "nested unevaluatedProperties, outer true, inner false, properties outside", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": { "type": "string" } - }, - "allOf": [ - { - "unevaluatedProperties": false - } - ], - "unevaluatedProperties": true - }, - "tests": [ - { - "description": "with no nested unevaluated properties", - "data": { - "foo": "foo" - }, - "valid": false - }, - { - "description": "with nested unevaluated properties", - "data": { - "foo": "foo", - "bar": "bar" - }, - "valid": false - } - ] - }, - { - "description": "nested unevaluatedProperties, outer true, inner false, properties inside", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [ - { - "properties": { - "foo": { "type": "string" } - }, - "unevaluatedProperties": false - } - ], - "unevaluatedProperties": true - }, - "tests": [ - { - "description": "with no nested unevaluated properties", - "data": { - "foo": "foo" - }, - "valid": true - }, - { - "description": "with nested unevaluated properties", - "data": { - "foo": "foo", - "bar": "bar" - }, - "valid": false - } - ] - }, - { - "description": "cousin unevaluatedProperties, true and false, true with properties", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [ - { - "properties": { - "foo": { "type": "string" } - }, - "unevaluatedProperties": true - }, - { - "unevaluatedProperties": false - } - ] - }, - "tests": [ - { - "description": "with no nested unevaluated properties", - "data": { - "foo": "foo" - }, - "valid": false - }, - { - "description": "with nested unevaluated properties", - "data": { - "foo": "foo", - "bar": "bar" - }, - "valid": false - } - ] - }, - { - "description": "cousin unevaluatedProperties, true and false, false with properties", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [ - { - "unevaluatedProperties": true - }, - { - "properties": { - "foo": { "type": "string" } - }, - "unevaluatedProperties": false - } - ] - }, - "tests": [ - { - "description": "with no nested unevaluated properties", - "data": { - "foo": "foo" - }, - "valid": true - }, - { - "description": "with nested unevaluated properties", - "data": { - "foo": "foo", - "bar": "bar" - }, - "valid": false - } - ] - }, - { - "description": "property is evaluated in an uncle schema to unevaluatedProperties", - "comment": "see https://stackoverflow.com/questions/66936884/deeply-nested-unevaluatedproperties-and-their-expectations", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": { - "properties": { - "bar": { - "type": "string" - } - }, - "unevaluatedProperties": false - } - }, - "anyOf": [ - { - "properties": { - "foo": { - "properties": { - "faz": { - "type": "string" - } - } - } - } - } - ] - }, - "tests": [ - { - "description": "no extra properties", - "data": { - "foo": { - "bar": "test" - } - }, - "valid": true - }, - { - "description": "uncle keyword evaluation is not significant", - "data": { - "foo": { - "bar": "test", - "faz": "test" - } - }, - "valid": false - } - ] - }, - { - "description": "in-place applicator siblings, allOf has unevaluated", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [ - { - "properties": { - "foo": true - }, - "unevaluatedProperties": false - } - ], - "anyOf": [ - { - "properties": { - "bar": true - } - } - ] - }, - "tests": [ - { - "description": "base case: both properties present", - "data": { - "foo": 1, - "bar": 1 - }, - "valid": false - }, - { - "description": "in place applicator siblings, bar is missing", - "data": { - "foo": 1 - }, - "valid": true - }, - { - "description": "in place applicator siblings, foo is missing", - "data": { - "bar": 1 - }, - "valid": false - } - ] - }, - { - "description": "in-place applicator siblings, anyOf has unevaluated", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "allOf": [ - { - "properties": { - "foo": true - } - } - ], - "anyOf": [ - { - "properties": { - "bar": true - }, - "unevaluatedProperties": false - } - ] - }, - "tests": [ - { - "description": "base case: both properties present", - "data": { - "foo": 1, - "bar": 1 - }, - "valid": false - }, - { - "description": "in place applicator siblings, bar is missing", - "data": { - "foo": 1 - }, - "valid": false - }, - { - "description": "in place applicator siblings, foo is missing", - "data": { - "bar": 1 - }, - "valid": true - } - ] - }, - { - "description": "unevaluatedProperties + single cyclic ref", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "x": { "$ref": "#" } - }, - "unevaluatedProperties": false - }, - "tests": [ - { - "description": "Empty is valid", - "data": {}, - "valid": true - }, - { - "description": "Single is valid", - "data": { "x": {} }, - "valid": true - }, - { - "description": "Unevaluated on 1st level is invalid", - "data": { "x": {}, "y": {} }, - "valid": false - }, - { - "description": "Nested is valid", - "data": { "x": { "x": {} } }, - "valid": true - }, - { - "description": "Unevaluated on 2nd level is invalid", - "data": { "x": { "x": {}, "y": {} } }, - "valid": false - }, - { - "description": "Deep nested is valid", - "data": { "x": { "x": { "x": {} } } }, - "valid": true - }, - { - "description": "Unevaluated on 3rd level is invalid", - "data": { "x": { "x": { "x": {}, "y": {} } } }, - "valid": false - } - ] - }, - { - "description": "unevaluatedProperties + ref inside allOf / oneOf", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$defs": { - "one": { - "properties": { "a": true } - }, - "two": { - "required": ["x"], - "properties": { "x": true } - } - }, - "allOf": [ - { "$ref": "#/$defs/one" }, - { "properties": { "b": true } }, - { - "oneOf": [ - { "$ref": "#/$defs/two" }, - { - "required": ["y"], - "properties": { "y": true } - } - ] - } - ], - "unevaluatedProperties": false - }, - "tests": [ - { - "description": "Empty is invalid (no x or y)", - "data": {}, - "valid": false - }, - { - "description": "a and b are invalid (no x or y)", - "data": { "a": 1, "b": 1 }, - "valid": false - }, - { - "description": "x and y are invalid", - "data": { "x": 1, "y": 1 }, - "valid": false - }, - { - "description": "a and x are valid", - "data": { "a": 1, "x": 1 }, - "valid": true - }, - { - "description": "a and y are valid", - "data": { "a": 1, "y": 1 }, - "valid": true - }, - { - "description": "a and b and x are valid", - "data": { "a": 1, "b": 1, "x": 1 }, - "valid": true - }, - { - "description": "a and b and y are valid", - "data": { "a": 1, "b": 1, "y": 1 }, - "valid": true - }, - { - "description": "a and b and x and y are invalid", - "data": { "a": 1, "b": 1, "x": 1, "y": 1 }, - "valid": false - } - ] - }, - { - "description": "dynamic evalation inside nested refs", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$defs": { - "one": { - "oneOf": [ - { "$ref": "#/$defs/two" }, - { "required": ["b"], "properties": { "b": true } }, - { "required": ["xx"], "patternProperties": { "x": true } }, - { "required": ["all"], "unevaluatedProperties": true } - ] - }, - "two": { - "oneOf": [ - { "required": ["c"], "properties": { "c": true } }, - { "required": ["d"], "properties": { "d": true } } - ] - } - }, - "oneOf": [ - { "$ref": "#/$defs/one" }, - { "required": ["a"], "properties": { "a": true } } - ], - "unevaluatedProperties": false - }, - "tests": [ - { - "description": "Empty is invalid", - "data": {}, - "valid": false - }, - { - "description": "a is valid", - "data": { "a": 1 }, - "valid": true - }, - { - "description": "b is valid", - "data": { "b": 1 }, - "valid": true - }, - { - "description": "c is valid", - "data": { "c": 1 }, - "valid": true - }, - { - "description": "d is valid", - "data": { "d": 1 }, - "valid": true - }, - { - "description": "a + b is invalid", - "data": { "a": 1, "b": 1 }, - "valid": false - }, - { - "description": "a + c is invalid", - "data": { "a": 1, "c": 1 }, - "valid": false - }, - { - "description": "a + d is invalid", - "data": { "a": 1, "d": 1 }, - "valid": false - }, - { - "description": "b + c is invalid", - "data": { "b": 1, "c": 1 }, - "valid": false - }, - { - "description": "b + d is invalid", - "data": { "b": 1, "d": 1 }, - "valid": false - }, - { - "description": "c + d is invalid", - "data": { "c": 1, "d": 1 }, - "valid": false - }, - { - "description": "xx is valid", - "data": { "xx": 1 }, - "valid": true - }, - { - "description": "xx + foox is valid", - "data": { "xx": 1, "foox": 1 }, - "valid": true - }, - { - "description": "xx + foo is invalid", - "data": { "xx": 1, "foo": 1 }, - "valid": false - }, - { - "description": "xx + a is invalid", - "data": { "xx": 1, "a": 1 }, - "valid": false - }, - { - "description": "xx + b is invalid", - "data": { "xx": 1, "b": 1 }, - "valid": false - }, - { - "description": "xx + c is invalid", - "data": { "xx": 1, "c": 1 }, - "valid": false - }, - { - "description": "xx + d is invalid", - "data": { "xx": 1, "d": 1 }, - "valid": false - }, - { - "description": "all is valid", - "data": { "all": 1 }, - "valid": true - }, - { - "description": "all + foo is valid", - "data": { "all": 1, "foo": 1 }, - "valid": true - }, - { - "description": "all + a is invalid", - "data": { "all": 1, "a": 1 }, - "valid": false - } - ] - }, - { - "description": "non-object instances are valid", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "unevaluatedProperties": false - }, - "tests": [ - { - "description": "ignores booleans", - "data": true, - "valid": true - }, - { - "description": "ignores integers", - "data": 123, - "valid": true - }, - { - "description": "ignores floats", - "data": 1.0, - "valid": true - }, - { - "description": "ignores arrays", - "data": [], - "valid": true - }, - { - "description": "ignores strings", - "data": "foo", - "valid": true - }, - { - "description": "ignores null", - "data": null, - "valid": true - } - ] - }, - { - "description": "unevaluatedProperties with null valued instance properties", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "unevaluatedProperties": { - "type": "null" - } - }, - "tests": [ - { - "description": "allows null valued properties", - "data": {"foo": null}, - "valid": true - } - ] - }, - { - "description": "unevaluatedProperties not affected by propertyNames", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "propertyNames": {"maxLength": 1}, - "unevaluatedProperties": { - "type": "number" - } - }, - "tests": [ - { - "description": "allows only number properties", - "data": {"a": 1}, - "valid": true - }, - { - "description": "string property is invalid", - "data": {"a": "b"}, - "valid": false - } - ] - }, - { - "description": "unevaluatedProperties can see annotations from if without then and else", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "if": { - "patternProperties": { - "foo": { - "type": "string" - } - } - }, - "unevaluatedProperties": false - }, - "tests": [ - { - "description": "valid in case if is evaluated", - "data": { - "foo": "a" - }, - "valid": true - }, - { - "description": "invalid in case if is evaluated", - "data": { - "bar": "a" - }, - "valid": false - } - ] - }, - { - "description": "dependentSchemas with unevaluatedProperties", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": {"foo2": {}}, - "dependentSchemas": { - "foo" : {}, - "foo2": { - "properties": { - "bar":{} - } - } - }, - "unevaluatedProperties": false - }, - "tests": [ - { - "description": "unevaluatedProperties doesn't consider dependentSchemas", - "data": {"foo": ""}, - "valid": false - }, - { - "description": "unevaluatedProperties doesn't see bar when foo2 is absent", - "data": {"bar": ""}, - "valid": false - }, - { - "description": "unevaluatedProperties sees bar when foo2 is present", - "data": { "foo2": "", "bar": ""}, - "valid": true - } - ] - }, - { - "description": "Evaluated properties collection needs to consider instance location", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "properties": { - "foo": { - "properties": { - "bar": { "type": "string" } - } - } - }, - "unevaluatedProperties": false - }, - "tests": [ - { - "description": "with an unevaluated property that exists at another location", - "data": { - "foo": { "bar": "foo" }, - "bar": "bar" - }, - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/uniqueItems.json b/tests/fixtures/json-schema-test-suite/draft2020-12/uniqueItems.json deleted file mode 100644 index 4ea3bf98..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/uniqueItems.json +++ /dev/null @@ -1,419 +0,0 @@ -[ - { - "description": "uniqueItems validation", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "uniqueItems": true - }, - "tests": [ - { - "description": "unique array of integers is valid", - "data": [1, 2], - "valid": true - }, - { - "description": "non-unique array of integers is invalid", - "data": [1, 1], - "valid": false - }, - { - "description": "non-unique array of more than two integers is invalid", - "data": [1, 2, 1], - "valid": false - }, - { - "description": "numbers are unique if mathematically unequal", - "data": [1.0, 1.00, 1], - "valid": false - }, - { - "description": "false is not equal to zero", - "data": [0, false], - "valid": true - }, - { - "description": "true is not equal to one", - "data": [1, true], - "valid": true - }, - { - "description": "unique array of strings is valid", - "data": ["foo", "bar", "baz"], - "valid": true - }, - { - "description": "non-unique array of strings is invalid", - "data": ["foo", "bar", "foo"], - "valid": false - }, - { - "description": "unique array of objects is valid", - "data": [{"foo": "bar"}, {"foo": "baz"}], - "valid": true - }, - { - "description": "non-unique array of objects is invalid", - "data": [{"foo": "bar"}, {"foo": "bar"}], - "valid": false - }, - { - "description": "property order of array of objects is ignored", - "data": [{"foo": "bar", "bar": "foo"}, {"bar": "foo", "foo": "bar"}], - "valid": false - }, - { - "description": "unique array of nested objects is valid", - "data": [ - {"foo": {"bar" : {"baz" : true}}}, - {"foo": {"bar" : {"baz" : false}}} - ], - "valid": true - }, - { - "description": "non-unique array of nested objects is invalid", - "data": [ - {"foo": {"bar" : {"baz" : true}}}, - {"foo": {"bar" : {"baz" : true}}} - ], - "valid": false - }, - { - "description": "unique array of arrays is valid", - "data": [["foo"], ["bar"]], - "valid": true - }, - { - "description": "non-unique array of arrays is invalid", - "data": [["foo"], ["foo"]], - "valid": false - }, - { - "description": "non-unique array of more than two arrays is invalid", - "data": [["foo"], ["bar"], ["foo"]], - "valid": false - }, - { - "description": "1 and true are unique", - "data": [1, true], - "valid": true - }, - { - "description": "0 and false are unique", - "data": [0, false], - "valid": true - }, - { - "description": "[1] and [true] are unique", - "data": [[1], [true]], - "valid": true - }, - { - "description": "[0] and [false] are unique", - "data": [[0], [false]], - "valid": true - }, - { - "description": "nested [1] and [true] are unique", - "data": [[[1], "foo"], [[true], "foo"]], - "valid": true - }, - { - "description": "nested [0] and [false] are unique", - "data": [[[0], "foo"], [[false], "foo"]], - "valid": true - }, - { - "description": "unique heterogeneous types are valid", - "data": [{}, [1], true, null, 1, "{}"], - "valid": true - }, - { - "description": "non-unique heterogeneous types are invalid", - "data": [{}, [1], true, null, {}, 1], - "valid": false - }, - { - "description": "different objects are unique", - "data": [{"a": 1, "b": 2}, {"a": 2, "b": 1}], - "valid": true - }, - { - "description": "objects are non-unique despite key order", - "data": [{"a": 1, "b": 2}, {"b": 2, "a": 1}], - "valid": false - }, - { - "description": "{\"a\": false} and {\"a\": 0} are unique", - "data": [{"a": false}, {"a": 0}], - "valid": true - }, - { - "description": "{\"a\": true} and {\"a\": 1} are unique", - "data": [{"a": true}, {"a": 1}], - "valid": true - } - ] - }, - { - "description": "uniqueItems with an array of items", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "prefixItems": [{"type": "boolean"}, {"type": "boolean"}], - "uniqueItems": true - }, - "tests": [ - { - "description": "[false, true] from items array is valid", - "data": [false, true], - "valid": true - }, - { - "description": "[true, false] from items array is valid", - "data": [true, false], - "valid": true - }, - { - "description": "[false, false] from items array is not valid", - "data": [false, false], - "valid": false - }, - { - "description": "[true, true] from items array is not valid", - "data": [true, true], - "valid": false - }, - { - "description": "unique array extended from [false, true] is valid", - "data": [false, true, "foo", "bar"], - "valid": true - }, - { - "description": "unique array extended from [true, false] is valid", - "data": [true, false, "foo", "bar"], - "valid": true - }, - { - "description": "non-unique array extended from [false, true] is not valid", - "data": [false, true, "foo", "foo"], - "valid": false - }, - { - "description": "non-unique array extended from [true, false] is not valid", - "data": [true, false, "foo", "foo"], - "valid": false - } - ] - }, - { - "description": "uniqueItems with an array of items and additionalItems=false", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "prefixItems": [{"type": "boolean"}, {"type": "boolean"}], - "uniqueItems": true, - "items": false - }, - "tests": [ - { - "description": "[false, true] from items array is valid", - "data": [false, true], - "valid": true - }, - { - "description": "[true, false] from items array is valid", - "data": [true, false], - "valid": true - }, - { - "description": "[false, false] from items array is not valid", - "data": [false, false], - "valid": false - }, - { - "description": "[true, true] from items array is not valid", - "data": [true, true], - "valid": false - }, - { - "description": "extra items are invalid even if unique", - "data": [false, true, null], - "valid": false - } - ] - }, - { - "description": "uniqueItems=false validation", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "uniqueItems": false - }, - "tests": [ - { - "description": "unique array of integers is valid", - "data": [1, 2], - "valid": true - }, - { - "description": "non-unique array of integers is valid", - "data": [1, 1], - "valid": true - }, - { - "description": "numbers are unique if mathematically unequal", - "data": [1.0, 1.00, 1], - "valid": true - }, - { - "description": "false is not equal to zero", - "data": [0, false], - "valid": true - }, - { - "description": "true is not equal to one", - "data": [1, true], - "valid": true - }, - { - "description": "unique array of objects is valid", - "data": [{"foo": "bar"}, {"foo": "baz"}], - "valid": true - }, - { - "description": "non-unique array of objects is valid", - "data": [{"foo": "bar"}, {"foo": "bar"}], - "valid": true - }, - { - "description": "unique array of nested objects is valid", - "data": [ - {"foo": {"bar" : {"baz" : true}}}, - {"foo": {"bar" : {"baz" : false}}} - ], - "valid": true - }, - { - "description": "non-unique array of nested objects is valid", - "data": [ - {"foo": {"bar" : {"baz" : true}}}, - {"foo": {"bar" : {"baz" : true}}} - ], - "valid": true - }, - { - "description": "unique array of arrays is valid", - "data": [["foo"], ["bar"]], - "valid": true - }, - { - "description": "non-unique array of arrays is valid", - "data": [["foo"], ["foo"]], - "valid": true - }, - { - "description": "1 and true are unique", - "data": [1, true], - "valid": true - }, - { - "description": "0 and false are unique", - "data": [0, false], - "valid": true - }, - { - "description": "unique heterogeneous types are valid", - "data": [{}, [1], true, null, 1], - "valid": true - }, - { - "description": "non-unique heterogeneous types are valid", - "data": [{}, [1], true, null, {}, 1], - "valid": true - } - ] - }, - { - "description": "uniqueItems=false with an array of items", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "prefixItems": [{"type": "boolean"}, {"type": "boolean"}], - "uniqueItems": false - }, - "tests": [ - { - "description": "[false, true] from items array is valid", - "data": [false, true], - "valid": true - }, - { - "description": "[true, false] from items array is valid", - "data": [true, false], - "valid": true - }, - { - "description": "[false, false] from items array is valid", - "data": [false, false], - "valid": true - }, - { - "description": "[true, true] from items array is valid", - "data": [true, true], - "valid": true - }, - { - "description": "unique array extended from [false, true] is valid", - "data": [false, true, "foo", "bar"], - "valid": true - }, - { - "description": "unique array extended from [true, false] is valid", - "data": [true, false, "foo", "bar"], - "valid": true - }, - { - "description": "non-unique array extended from [false, true] is valid", - "data": [false, true, "foo", "foo"], - "valid": true - }, - { - "description": "non-unique array extended from [true, false] is valid", - "data": [true, false, "foo", "foo"], - "valid": true - } - ] - }, - { - "description": "uniqueItems=false with an array of items and additionalItems=false", - "schema": { - "$schema": "https://json-schema.org/draft/2020-12/schema", - "prefixItems": [{"type": "boolean"}, {"type": "boolean"}], - "uniqueItems": false, - "items": false - }, - "tests": [ - { - "description": "[false, true] from items array is valid", - "data": [false, true], - "valid": true - }, - { - "description": "[true, false] from items array is valid", - "data": [true, false], - "valid": true - }, - { - "description": "[false, false] from items array is valid", - "data": [false, false], - "valid": true - }, - { - "description": "[true, true] from items array is valid", - "data": [true, true], - "valid": true - }, - { - "description": "extra items are invalid even if unique", - "data": [false, true, null], - "valid": false - } - ] - } -] diff --git a/tests/fixtures/json-schema-test-suite/draft2020-12/vocabulary.json b/tests/fixtures/json-schema-test-suite/draft2020-12/vocabulary.json deleted file mode 100644 index 1acb96a9..00000000 --- a/tests/fixtures/json-schema-test-suite/draft2020-12/vocabulary.json +++ /dev/null @@ -1,57 +0,0 @@ -[ - { - "description": "schema that uses custom metaschema with with no validation vocabulary", - "schema": { - "$id": "https://schema/using/no/validation", - "$schema": "http://localhost:1234/draft2020-12/metaschema-no-validation.json", - "properties": { - "badProperty": false, - "numberProperty": { - "minimum": 10 - } - } - }, - "tests": [ - { - "description": "applicator vocabulary still works", - "data": { - "badProperty": "this property should not exist" - }, - "valid": false - }, - { - "description": "no validation: valid number", - "data": { - "numberProperty": 20 - }, - "valid": true - }, - { - "description": "no validation: invalid number, but it still validates", - "data": { - "numberProperty": 1 - }, - "valid": true - } - ] - }, - { - "description": "ignore unrecognized optional vocabulary", - "schema": { - "$schema": "http://localhost:1234/draft2020-12/metaschema-optional-vocabulary.json", - "type": "number" - }, - "tests": [ - { - "description": "string value", - "data": "foobar", - "valid": false - }, - { - "description": "number value", - "data": 20, - "valid": true - } - ] - } -] diff --git a/tests/json_schema_test_suite.rs b/tests/json_schema_test_suite.rs deleted file mode 100644 index d7bf2c63..00000000 --- a/tests/json_schema_test_suite.rs +++ /dev/null @@ -1,501 +0,0 @@ -//! Integration tests for JSON Schema Test Suite compatibility -//! -//! This module tests that schemars-docgen can generate HTML documentation -//! for all schemas in the JSON-Schema-Test-Suite draft2020-12 examples -//! without crashing. - -use chrono::Local; -use chrono::Utc; -use rayon::prelude::*; -use serde::Deserialize; -use serde::Serialize; -use std::collections::BTreeMap; -use std::fs; -use std::path::Path; -use std::path::PathBuf; -use std::process::Command; -use std::sync::Mutex; -use std::sync::atomic::AtomicUsize; -use std::sync::atomic::Ordering; -use tera::Context; -use tera::Tera; - -/// Represents a test suite from the JSON Schema Test Suite -#[derive(Debug, Deserialize)] -struct TestSuite { - description: String, - schema: serde_json::Value, - #[serde(default)] - #[allow(dead_code)] - tests: Vec, -} - -/// A schema test case with all context needed for parallel execution -#[derive(Debug)] -struct SchemaTestCase { - #[allow(dead_code)] - file_path: PathBuf, - relative_path: String, - index: usize, - description: String, - schema: serde_json::Value, - output_path: PathBuf, -} - -/// Get the project root directory -fn project_root() -> PathBuf { - PathBuf::from(env!("CARGO_MANIFEST_DIR")) -} - -/// Get the fixtures directory -fn fixtures_dir() -> PathBuf { - project_root().join("tests/fixtures/json-schema-test-suite/draft2020-12") -} - -/// Get the test output directory -fn output_dir() -> PathBuf { - project_root().join("tests/outputs/json-schema-test-suite/draft2020-12") -} - -/// Extract all schemas from a test suite file -fn extract_schemas(file_path: &Path) -> Vec<(String, serde_json::Value)> { - let content = fs::read_to_string(file_path).expect("Failed to read test file"); - let suites: Vec = serde_json::from_str(&content).expect("Failed to parse test file"); - - suites - .into_iter() - .map(|suite| (suite.description, suite.schema)) - .collect() -} - -/// Run the CLI against a schema and return success/failure -fn run_cli(schema: &serde_json::Value, output_path: &Path) -> Result<(), String> { - // Create a unique temporary file for the schema (use thread id to avoid conflicts) - let temp_dir = std::env::temp_dir(); - let schema_file = temp_dir.join(format!( - "test_schema_{:?}_{}.json", - std::thread::current().id(), - std::time::SystemTime::now() - .duration_since(std::time::UNIX_EPOCH) - .unwrap() - .as_nanos() - )); - - fs::write(&schema_file, serde_json::to_string_pretty(schema).unwrap()) - .map_err(|e| format!("Failed to write schema file: {}", e))?; - - // Ensure output directory exists - if let Some(parent) = output_path.parent() { - fs::create_dir_all(parent) - .map_err(|e| format!("Failed to create output directory: {}", e))?; - } - - // Run the CLI - let output = Command::new(env!("CARGO_BIN_EXE_schemars-docgen")) - .arg(&schema_file) - .arg("-o") - .arg(output_path) - .output() - .map_err(|e| format!("Failed to execute CLI: {}", e))?; - - // Clean up temp file - let _ = fs::remove_file(&schema_file); - - if output.status.success() { - Ok(()) - } else { - let stderr = String::from_utf8_lossy(&output.stderr); - let stdout = String::from_utf8_lossy(&output.stdout); - Err(format!( - "CLI failed with status {:?}\nstderr: {}\nstdout: {}", - output.status.code(), - stderr, - stdout - )) - } -} - -/// Collect all JSON test files from a directory recursively -fn collect_test_files(dir: &Path) -> Vec { - let mut files = Vec::new(); - - if dir.is_dir() { - for entry in fs::read_dir(dir).expect("Failed to read directory") { - let entry = entry.expect("Failed to read entry"); - let path = entry.path(); - - if path.is_dir() { - files.extend(collect_test_files(&path)); - } else if path.extension().is_some_and(|ext| ext == "json") { - files.push(path); - } - } - } - - files.sort(); - files -} - -/// Convert a fixture file path to its corresponding output directory -fn fixture_to_output_dir(fixture_path: &Path) -> PathBuf { - let fixtures_base = fixtures_dir(); - let relative = fixture_path - .strip_prefix(&fixtures_base) - .expect("Fixture path should be under fixtures dir"); - - // Remove .json extension and use as directory name - let stem = relative.with_extension(""); - output_dir().join(stem) -} - -/// Collect all test cases from all fixture files -fn collect_all_test_cases() -> Vec { - let fixtures = fixtures_dir(); - let test_files = collect_test_files(&fixtures); - - test_files - .into_iter() - .flat_map(|file_path| { - let schemas = extract_schemas(&file_path); - let output_base = fixture_to_output_dir(&file_path); - let relative_path = file_path - .strip_prefix(&fixtures) - .unwrap_or(&file_path) - .display() - .to_string(); - - schemas - .into_iter() - .enumerate() - .map(move |(idx, (description, schema))| SchemaTestCase { - file_path: file_path.clone(), - relative_path: relative_path.clone(), - index: idx, - description, - schema, - output_path: output_base.join(format!("{}.html", idx)), - }) - }) - .collect() -} - -/// Data structure for a schema entry in the index template -#[derive(Debug, Serialize)] -struct IndexSchema { - index: usize, - description: String, - output_path: String, - has_content: bool, - features: Vec, -} - -/// Data structure for a file group in the index template -#[derive(Debug, Serialize)] -struct IndexGroup { - file_path: String, - schemas: Vec, -} - -/// Analyze a schema and return (has_content, features) -/// has_content is true if the schema has properties or $defs (will show Configuration/Types) -/// features lists the JSON Schema keywords present in the schema -fn analyze_schema(schema: &serde_json::Value) -> (bool, Vec) { - let mut features = Vec::new(); - - let obj = match schema.as_object() { - Some(o) => o, - None => { - // Handle boolean schemas - if schema.as_bool() == Some(true) { - return (false, vec!["boolean: true".to_string()]); - } else if schema.as_bool() == Some(false) { - return (false, vec!["boolean: false".to_string()]); - } - return (false, vec!["non-object".to_string()]); - } - }; - - if obj.is_empty() { - return (false, vec!["empty schema".to_string()]); - } - - let has_properties = obj.contains_key("properties"); - let has_defs = obj.contains_key("$defs") || obj.contains_key("definitions"); - - // Collect features - if has_properties { - features.push("properties".to_string()); - } - if has_defs { - features.push("$defs".to_string()); - } - if obj.contains_key("$ref") { - features.push("$ref".to_string()); - } - if let Some(t) = obj.get("type") { - if let Some(s) = t.as_str() { - features.push(format!("type: {}", s)); - } else if let Some(arr) = t.as_array() { - let types: Vec<_> = arr.iter().filter_map(|v| v.as_str()).collect(); - features.push(format!("type: [{}]", types.join(", "))); - } - } - if obj.contains_key("items") { - features.push("items".to_string()); - } - if obj.contains_key("prefixItems") { - features.push("prefixItems".to_string()); - } - if obj.contains_key("additionalProperties") { - features.push("additionalProperties".to_string()); - } - if obj.contains_key("patternProperties") { - features.push("patternProperties".to_string()); - } - if obj.contains_key("allOf") { - features.push("allOf".to_string()); - } - if obj.contains_key("anyOf") { - features.push("anyOf".to_string()); - } - if obj.contains_key("oneOf") { - features.push("oneOf".to_string()); - } - if obj.contains_key("not") { - features.push("not".to_string()); - } - if obj.contains_key("if") { - features.push("if/then/else".to_string()); - } - if obj.contains_key("const") { - features.push("const".to_string()); - } - if obj.contains_key("enum") { - features.push("enum".to_string()); - } - if obj.contains_key("$dynamicRef") { - features.push("$dynamicRef".to_string()); - } - if obj.contains_key("$dynamicAnchor") { - features.push("$dynamicAnchor".to_string()); - } - if obj.contains_key("contains") { - features.push("contains".to_string()); - } - if obj.contains_key("dependentSchemas") { - features.push("dependentSchemas".to_string()); - } - if obj.contains_key("dependentRequired") { - features.push("dependentRequired".to_string()); - } - if obj.contains_key("unevaluatedItems") { - features.push("unevaluatedItems".to_string()); - } - if obj.contains_key("unevaluatedProperties") { - features.push("unevaluatedProperties".to_string()); - } - - // If no features found, list what keys are present - if features.is_empty() { - let keys: Vec<_> = obj.keys().take(3).cloned().collect(); - features.push(format!("other: {}", keys.join(", "))); - } - - (has_properties || has_defs, features) -} - -/// Get git commit hash -fn get_git_commit_hash() -> String { - Command::new("git") - .args(["rev-parse", "HEAD"]) - .output() - .ok() - .and_then(|o| { - if o.status.success() { - String::from_utf8(o.stdout) - .ok() - .map(|s| s.trim().to_string()) - } else { - None - } - }) - .unwrap_or_else(|| "unknown".to_string()) -} - -/// Check if git repo is dirty -fn is_git_dirty() -> bool { - Command::new("git") - .args(["status", "--porcelain"]) - .output() - .ok() - .map(|o| !o.stdout.is_empty()) - .unwrap_or(false) -} - -/// Generate an index.html file with links to all test outputs using Tera -fn generate_index_html(test_cases: &[SchemaTestCase]) { - let output_base = project_root().join("tests/outputs"); - let index_path = output_base.join("index.html"); - - // Group test cases by their source file (relative_path) - let mut grouped: BTreeMap> = BTreeMap::new(); - for test_case in test_cases { - grouped - .entry(test_case.relative_path.clone()) - .or_default() - .push(test_case); - } - - // Convert to template-friendly structure - let mut with_content = 0; - let mut without_content = 0; - - let groups: Vec = grouped - .into_iter() - .map(|(file_path, cases)| { - let schemas = cases - .into_iter() - .map(|case| { - let relative_output = case - .output_path - .strip_prefix(&output_base) - .expect("Output path should be under output base"); - let (has_content, features) = analyze_schema(&case.schema); - if has_content { - with_content += 1; - } else { - without_content += 1; - } - IndexSchema { - index: case.index, - description: case.description.clone(), - output_path: relative_output.display().to_string(), - has_content, - features, - } - }) - .collect(); - IndexGroup { file_path, schemas } - }) - .collect(); - - // Load and render template - let template_path = project_root().join("src/templates/test_index.html"); - let template_content = - fs::read_to_string(&template_path).expect("Failed to read test_index.html template"); - - let mut tera = Tera::default(); - tera.add_raw_template("test_index.html", &template_content) - .expect("Failed to parse template"); - - // Get git and time info - let commit_hash = get_git_commit_hash(); - let is_dirty = is_git_dirty(); - let time_utc = Utc::now().format("%Y-%m-%d %H:%M:%S UTC").to_string(); - let time_local = Local::now().format("%Y-%m-%d %H:%M:%S %Z").to_string(); - - let mut context = Context::new(); - context.insert("total_schemas", &test_cases.len()); - context.insert("total_files", &groups.len()); - context.insert("with_content", &with_content); - context.insert("without_content", &without_content); - context.insert("commit_hash", &commit_hash); - context.insert("is_dirty", &is_dirty); - context.insert("time_utc", &time_utc); - context.insert("time_local", &time_local); - context.insert("groups", &groups); - - let html = tera - .render("test_index.html", &context) - .expect("Failed to render template"); - - fs::write(&index_path, html).expect("Failed to write index.html"); - println!("Generated index.html at {:?}", index_path); -} - -#[test] -fn test_all_json_schema_test_suite_schemas() { - let fixtures = fixtures_dir(); - if !fixtures.exists() { - panic!( - "Fixtures directory not found: {:?}\n\ - Please run: git clone --depth 1 https://github.com/json-schema-org/JSON-Schema-Test-Suite.git /tmp/json-schema-test-suite && \ - mkdir -p fixtures/json-schema-test-suite && \ - cp -r /tmp/json-schema-test-suite/tests/draft2020-12 fixtures/json-schema-test-suite/ && \ - rm -rf /tmp/json-schema-test-suite", - fixtures - ); - } - - // Collect all test cases upfront - let test_cases = collect_all_test_cases(); - let total_schemas = test_cases.len(); - println!("Found {} schemas to test", total_schemas); - - // Counters for progress - let passed = AtomicUsize::new(0); - type FailedTest = (String, usize, String, serde_json::Value, String); - let failed: Mutex> = Mutex::new(Vec::new()); - - // Run tests in parallel - test_cases.par_iter().for_each(|test_case| { - match run_cli(&test_case.schema, &test_case.output_path) { - Ok(()) => { - passed.fetch_add(1, Ordering::Relaxed); - } - Err(e) => { - failed.lock().unwrap().push(( - test_case.relative_path.clone(), - test_case.index, - test_case.description.clone(), - test_case.schema.clone(), - e, - )); - } - } - }); - - let passed_count = passed.load(Ordering::Relaxed); - let failed_list = failed.into_inner().unwrap(); - - println!("\n=== Summary ==="); - println!("Total schemas: {}", total_schemas); - println!("Passed: {}", passed_count); - println!("Failed: {}", failed_list.len()); - - if !failed_list.is_empty() { - println!("\n=== Failed Schemas ==="); - for (relative_path, idx, desc, schema, error) in &failed_list { - println!("\n--- {}[{}]: {} ---", relative_path, idx, desc); - println!("Schema: {}", serde_json::to_string_pretty(schema).unwrap()); - println!("Error: {}", error); - } - panic!( - "{} schemas failed to generate documentation", - failed_list.len() - ); - } - - // Generate index.html with links to all outputs - generate_index_html(&test_cases); -} - -/// Test a single schema file - useful for debugging specific failures -#[test] -#[ignore] -fn test_single_schema_file() { - let file_path = fixtures_dir().join("type.json"); - let schemas = extract_schemas(&file_path); - let output_base = fixture_to_output_dir(&file_path); - - for (idx, (description, schema)) in schemas.iter().enumerate() { - let output_path = output_base.join(format!("{}.html", idx)); - println!("Testing: {} - {}", idx, description); - println!("Schema: {}", serde_json::to_string_pretty(schema).unwrap()); - - match run_cli(schema, &output_path) { - Ok(()) => println!(" PASS"), - Err(e) => panic!(" FAIL: {}", e), - } - } -}