From 4141c39f100858178865529668b44138e0900b27 Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Thu, 5 Feb 2026 12:35:28 -0400 Subject: [PATCH] Speed up framing, linting, and compilation Signed-off-by: Juan Cruz Viotti --- DEPENDENCIES | 10 +- src/index/generators.h | 2 +- vendor/blaze/CMakeLists.txt | 1 - vendor/blaze/package-lock.json | 957 ------------------ vendor/blaze/package.json | 77 -- vendor/blaze/src/compiler/compile.cc | 92 +- .../include/sourcemeta/blaze/compiler.h | 22 +- .../include/sourcemeta/blaze/compiler_error.h | 22 + vendor/blaze/src/compiler/unevaluated.cc | 66 +- .../linter/include/sourcemeta/blaze/linter.h | 3 + vendor/blaze/src/linter/valid_default.cc | 41 +- vendor/blaze/src/linter/valid_examples.cc | 48 +- vendor/blaze/src/test/test_parser.cc | 4 +- vendor/codegen/src/ir/ir.cc | 3 +- vendor/core/src/core/jsonschema/frame.cc | 411 +++++--- .../sourcemeta/core/jsonschema_frame.h | 67 +- .../sourcemeta/core/jsonschema_transform.h | 7 +- .../core/src/core/jsonschema/transformer.cc | 4 +- .../alterschema/common/orphan_definitions.h | 33 +- vendor/jsonbinpack/src/compiler/compiler.cc | 8 +- vendor/jsonschema/VERSION | 2 +- vendor/jsonschema/src/command_canonicalize.cc | 3 +- vendor/jsonschema/src/command_compile.cc | 40 +- vendor/jsonschema/src/command_lint.cc | 106 +- vendor/jsonschema/src/command_metaschema.cc | 4 +- vendor/jsonschema/src/command_validate.cc | 32 +- vendor/jsonschema/src/error.h | 10 + vendor/jsonschema/src/main.cc | 16 +- vendor/jsonschema/src/utils.h | 31 + 29 files changed, 737 insertions(+), 1385 deletions(-) delete mode 100644 vendor/blaze/package-lock.json delete mode 100644 vendor/blaze/package.json diff --git a/DEPENDENCIES b/DEPENDENCIES index 243f6f41..ca986963 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -1,11 +1,11 @@ vendorpull https://github.com/sourcemeta/vendorpull 1dcbac42809cf87cb5b045106b863e17ad84ba02 uwebsockets https://github.com/uNetworking/uWebSockets v20.74.0 -core https://github.com/sourcemeta/core 6d1acddbe4888f0ca3b98a13f13f7b1fa44be964 -blaze https://github.com/sourcemeta/blaze ed6889f138b0b446cce79e5adb4c7facaefd6846 -jsonbinpack https://github.com/sourcemeta/jsonbinpack 5e0e10c4550a2e5d4c13af037d3bb295acb19726 +core https://github.com/sourcemeta/core 8067ad94fb963e0d60c6d2092846b99d048319b0 +blaze https://github.com/sourcemeta/blaze 8f44f7dd663994a35bed23f986995704a4d1dade +jsonbinpack https://github.com/sourcemeta/jsonbinpack 3898774a945ebf7392bad8a9015ead97a0518a19 hydra https://github.com/sourcemeta/hydra c86d2165a2f27f838837af1a5af24b1055a35317 -codegen https://github.com/sourcemeta/codegen f1c1cc50799b69ce8a5bb970e606f229b7fe60a1 -jsonschema https://github.com/sourcemeta/jsonschema v14.6.0 +codegen https://github.com/sourcemeta/codegen 7733b3071cb140bc0d09406ebb9c3f306d71f7bf +jsonschema https://github.com/sourcemeta/jsonschema 081c3b70e09b408a35a513f4727ac7b93d469885 bootstrap https://github.com/twbs/bootstrap v5.3.3 bootstrap-icons https://github.com/twbs/icons v1.11.3 collections/sourcemeta/std/v0 https://github.com/sourcemeta/std v0.4.0 diff --git a/src/index/generators.h b/src/index/generators.h index 17e17604..ffa8eec8 100644 --- a/src/index/generators.h +++ b/src/index/generators.h @@ -347,7 +347,7 @@ struct GENERATE_HEALTH { return resolver(identifier, callback); }, [&errors](const auto &pointer, const auto &name, const auto &message, - const auto &outcome) { + const auto &outcome, const bool) { auto entry{sourcemeta::core::JSON::make_object()}; entry.assign("name", sourcemeta::core::JSON{name}); entry.assign("message", sourcemeta::core::JSON{message}); diff --git a/vendor/blaze/CMakeLists.txt b/vendor/blaze/CMakeLists.txt index f8a49686..dc88d4f3 100644 --- a/vendor/blaze/CMakeLists.txt +++ b/vendor/blaze/CMakeLists.txt @@ -79,7 +79,6 @@ endif() if(PROJECT_IS_TOP_LEVEL) sourcemeta_target_clang_format(SOURCES - bindings/nodejs/src/*.cc bindings/nodejs/src/*.h contrib/*.cc src/*.h src/*.cc benchmark/*.h benchmark/*.cc diff --git a/vendor/blaze/package-lock.json b/vendor/blaze/package-lock.json deleted file mode 100644 index ae056c72..00000000 --- a/vendor/blaze/package-lock.json +++ /dev/null @@ -1,957 +0,0 @@ -{ - "name": "@sourcemeta/blaze", - "version": "0.0.1", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@sourcemeta/blaze", - "version": "0.0.1", - "hasInstallScript": true, - "license": "AGPL-3.0", - "dependencies": { - "cmake-js": "^7.3.0" - }, - "devDependencies": { - "benchmark": "^2.1.4" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/aproba": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz", - "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==", - "license": "ISC" - }, - "node_modules/are-we-there-yet": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", - "deprecated": "This package is no longer supported.", - "license": "ISC", - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT" - }, - "node_modules/axios": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", - "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.4", - "proxy-from-env": "^1.1.0" - } - }, - "node_modules/benchmark": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-2.1.4.tgz", - "integrity": "sha512-l9MlfN4M1K/H2fbhfMy3B7vJd6AGKJVQn2h6Sg/Yx+KckoUA7ewS5Vv6TjSq18ooE1kS9hhAlQRH3AkXIh/aOQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "lodash": "^4.17.4", - "platform": "^1.3.3" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/cmake-js": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/cmake-js/-/cmake-js-7.4.0.tgz", - "integrity": "sha512-Lw0JxEHrmk+qNj1n9W9d4IvkDdYTBn7l2BW6XmtLj7WPpIo2shvxUy+YokfjMxAAOELNonQwX3stkPhM5xSC2Q==", - "license": "MIT", - "dependencies": { - "axios": "^1.6.5", - "debug": "^4", - "fs-extra": "^11.2.0", - "memory-stream": "^1.0.0", - "node-api-headers": "^1.1.0", - "npmlog": "^6.0.2", - "rc": "^1.2.7", - "semver": "^7.5.4", - "tar": "^6.2.0", - "url-join": "^4.0.1", - "which": "^2.0.2", - "yargs": "^17.7.2" - }, - "bin": { - "cmake-js": "bin/cmake-js" - }, - "engines": { - "node": ">= 14.15.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" - }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "license": "ISC", - "bin": { - "color-support": "bin.js" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "license": "ISC" - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "license": "MIT", - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "license": "MIT" - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fs-extra": { - "version": "11.3.2", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.2.tgz", - "integrity": "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "deprecated": "This package is no longer supported.", - "license": "ISC", - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "license": "ISC", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC" - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "license": "ISC" - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "license": "ISC" - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/jsonfile": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", - "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true, - "license": "MIT" - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/memory-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/memory-stream/-/memory-stream-1.0.0.tgz", - "integrity": "sha512-Wm13VcsPIMdG96dzILfij09PvuS3APtcKNh7M28FsCA/w6+1mjR7hhPmfFNoilX9xU7wTdhsH5lJAm6XNzdtww==", - "license": "MIT", - "dependencies": { - "readable-stream": "^3.4.0" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "license": "ISC", - "engines": { - "node": ">=8" - } - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "license": "MIT", - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/node-api-headers": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/node-api-headers/-/node-api-headers-1.7.0.tgz", - "integrity": "sha512-uJMGdkhVwu9+I3UsVvI3KW6ICAy/yDfsu5Br9rSnTtY3WpoaComXvKloiV5wtx0Md2rn0B9n29Ys2WMNwWxj9A==", - "license": "MIT" - }, - "node_modules/npmlog": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "deprecated": "This package is no longer supported.", - "license": "ISC", - "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/platform": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz", - "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==", - "dev": true, - "license": "MIT" - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "license": "ISC" - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "license": "ISC" - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "license": "ISC", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/url-join": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", - "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", - "license": "MIT" - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "license": "ISC", - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "license": "MIT", - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "license": "ISC", - "engines": { - "node": ">=12" - } - } - } -} diff --git a/vendor/blaze/package.json b/vendor/blaze/package.json deleted file mode 100644 index ac6d7d05..00000000 --- a/vendor/blaze/package.json +++ /dev/null @@ -1,77 +0,0 @@ -{ - "name": "@sourcemeta/blaze", - "version": "0.0.1", - "description": "The ultra high-performance JSON Schema evaluator", - "type": "module", - "main": "bindings/nodejs/src/index.js", - "exports": { - ".": { - "import": "./bindings/nodejs/src/index.js" - } - }, - "scripts": { - "install": "cmake-js compile --directory bindings/nodejs", - "build": "cmake-js compile --directory bindings/nodejs", - "build:debug": "cmake-js compile --debug --directory bindings/nodejs", - "rebuild": "cmake-js rebuild --directory bindings/nodejs", - "clean": "cmake-js clean --directory bindings/nodejs", - "test": "node --test bindings/nodejs/test/*.test.js", - "benchmark": "node bindings/nodejs/benchmark.js" - }, - "repository": { - "type": "git", - "url": "https://github.com/sourcemeta/blaze" - }, - "keywords": [ - "json", - "json-schema", - "validator", - "validation", - "schema" - ], - "author": "Sourcemeta", - "license": "AGPL-3.0", - "bugs": { - "url": "https://github.com/sourcemeta/blaze/issues" - }, - "homepage": "https://github.com/sourcemeta/blaze", - "dependencies": { - "cmake-js": "^7.3.0" - }, - "engines": { - "node": ">=18.0.0" - }, - "files": [ - "bindings/nodejs/src/", - "bindings/nodejs/CMakeLists.txt", - "cmake/", - "CMakeLists.txt", - "src/compiler/", - "src/evaluator/", - "src/output/", - "vendor/core/cmake/", - "vendor/core/CMakeLists.txt", - "vendor/core/config.cmake.in", - "vendor/core/src/lang/io/", - "vendor/core/src/lang/numeric/", - "vendor/core/src/core/json/", - "vendor/core/src/core/jsonpointer/", - "vendor/core/src/core/jsonschema/", - "vendor/core/src/core/regex/", - "vendor/core/src/core/uri/", - "vendor/core/vendor/mpdecimal/", - "vendor/core/vendor/pcre2/", - "vendor/core/vendor/jsonschema-2019-09/", - "vendor/core/vendor/jsonschema-2020-12/", - "vendor/core/vendor/jsonschema-draft0/", - "vendor/core/vendor/jsonschema-draft1/", - "vendor/core/vendor/jsonschema-draft2/", - "vendor/core/vendor/jsonschema-draft3/", - "vendor/core/vendor/jsonschema-draft4/", - "vendor/core/vendor/jsonschema-draft6/", - "vendor/core/vendor/jsonschema-draft7/" - ], - "devDependencies": { - "benchmark": "^2.1.4" - } -} diff --git a/vendor/blaze/src/compiler/compile.cc b/vendor/blaze/src/compiler/compile.cc index 48b18cf6..18ab91e2 100644 --- a/vendor/blaze/src/compiler/compile.cc +++ b/vendor/blaze/src/compiler/compile.cc @@ -154,31 +154,27 @@ auto compile(const sourcemeta::core::JSON &schema, const sourcemeta::core::SchemaWalker &walker, const sourcemeta::core::SchemaResolver &resolver, const Compiler &compiler, - const sourcemeta::core::SchemaFrame &frame, const Mode mode, - const std::string_view default_dialect, - const std::string_view default_id, + const sourcemeta::core::SchemaFrame &frame, + const std::string_view entrypoint, const Mode mode, const std::optional &tweaks) -> Template { assert(is_schema(schema)); const auto effective_tweaks{tweaks.value_or(Tweaks{})}; - /////////////////////////////////////////////////////////////////// - // (1) Determine the root frame entry - /////////////////////////////////////////////////////////////////// + const auto maybe_entrypoint_location{frame.traverse(entrypoint)}; + if (!maybe_entrypoint_location.has_value()) { + throw CompilerInvalidEntryPoint{ + entrypoint, "The given entry point URI does not exist in the schema"}; + } - const auto base_dialect{ - sourcemeta::core::base_dialect(schema, resolver, default_dialect)}; - const auto identifier{ - base_dialect.has_value() - ? sourcemeta::core::identify(schema, base_dialect.value(), default_id) - : std::string_view{}}; - const std::string base{sourcemeta::core::URI::canonicalize(identifier)}; - assert(frame.locations().contains( - {sourcemeta::core::SchemaReferenceType::Static, base})); - const auto root_frame_entry{frame.locations().at( - {sourcemeta::core::SchemaReferenceType::Static, base})}; + const auto &entrypoint_location{maybe_entrypoint_location->get()}; + if (entrypoint_location.type == + sourcemeta::core::SchemaFrame::LocationType::Pointer) { + throw CompilerInvalidEntryPoint{ + entrypoint, "The given entry point URI is not a valid subschema"}; + } /////////////////////////////////////////////////////////////////// - // (2) Determine all the schema resources in the schema + // (1) Determine all the schema resources in the schema /////////////////////////////////////////////////////////////////// std::vector resources; @@ -198,7 +194,7 @@ auto compile(const sourcemeta::core::JSON &schema, std::set(resources.cbegin(), resources.cend()).size()); /////////////////////////////////////////////////////////////////// - // (3) Check if the schema relies on dynamic scopes + // (2) Check if the schema relies on dynamic scopes /////////////////////////////////////////////////////////////////// bool uses_dynamic_scopes{false}; @@ -213,7 +209,7 @@ auto compile(const sourcemeta::core::JSON &schema, } /////////////////////////////////////////////////////////////////// - // (4) Plan which static references we will precompile + // (3) Plan which static references we will precompile /////////////////////////////////////////////////////////////////// std::unordered_map> target_types; @@ -224,8 +220,8 @@ auto compile(const sourcemeta::core::JSON &schema, std::pair> targets_map; targets_map.emplace( - std::make_tuple(sourcemeta::core::SchemaReferenceType::Static, - std::string_view{frame.root()}, false), + std::make_tuple(sourcemeta::core::SchemaReferenceType::Static, entrypoint, + false), std::make_pair(0, nullptr)); for (const auto &reference : frame.references()) { @@ -248,7 +244,8 @@ auto compile(const sourcemeta::core::JSON &schema, // Skip unreachable targets if (reference_origin->get().type != sourcemeta::core::SchemaFrame::LocationType::Pointer && - !frame.is_reachable(reference_origin->get(), walker, resolver)) { + !frame.is_reachable(entrypoint_location, reference_origin->get(), + walker, resolver)) { continue; } @@ -282,7 +279,8 @@ auto compile(const sourcemeta::core::JSON &schema, } // Skip unreachable dynamic anchors - if (!frame.is_reachable(entry.second, walker, resolver)) { + if (!frame.is_reachable(entrypoint_location, entry.second, walker, + resolver)) { continue; } @@ -293,7 +291,7 @@ auto compile(const sourcemeta::core::JSON &schema, } /////////////////////////////////////////////////////////////////// - // (5) Build the global compilation context + // (4) Build the global compilation context /////////////////////////////////////////////////////////////////// auto unevaluated{ @@ -312,7 +310,7 @@ auto compile(const sourcemeta::core::JSON &schema, .targets = std::move(targets_map)}; /////////////////////////////////////////////////////////////////// - // (6) Build labels map for dynamic anchors + // (5) Build labels map for dynamic anchors /////////////////////////////////////////////////////////////////// std::vector> labels_map; @@ -326,8 +324,8 @@ auto compile(const sourcemeta::core::JSON &schema, } // Skip unreachable dynamic anchors - if (!context.frame.is_reachable(entry.second, context.walker, - context.resolver)) { + if (!context.frame.is_reachable(entrypoint_location, entry.second, + context.walker, context.resolver)) { continue; } @@ -352,7 +350,7 @@ auto compile(const sourcemeta::core::JSON &schema, } /////////////////////////////////////////////////////////////////// - // (7) Compile targets for static references + // (6) Compile targets for static references /////////////////////////////////////////////////////////////////// std::vector compiled_targets; @@ -397,7 +395,7 @@ auto compile(const sourcemeta::core::JSON &schema, } /////////////////////////////////////////////////////////////////// - // (8) Postprocess compiled targets + // (7) Postprocess compiled targets /////////////////////////////////////////////////////////////////// if (mode == Mode::FastValidation) { @@ -405,12 +403,12 @@ auto compile(const sourcemeta::core::JSON &schema, } /////////////////////////////////////////////////////////////////// - // (9) Return final template + // (8) Return final template /////////////////////////////////////////////////////////////////// const bool track{ context.mode != Mode::FastValidation || - requires_evaluation(context, root_frame_entry.pointer) || + requires_evaluation(context, entrypoint_location.pointer) || // TODO: This expression should go away if we start properly compiling // `unevaluatedItems` like we compile `unevaluatedProperties` std::ranges::any_of(context.unevaluated, [](const auto &dependency) { @@ -428,28 +426,20 @@ auto compile(const sourcemeta::core::JSON &schema, const Compiler &compiler, const Mode mode, const std::string_view default_dialect, const std::string_view default_id, + const std::string_view entrypoint, const std::optional &tweaks) -> Template { assert(is_schema(schema)); - const auto effective_tweaks{tweaks.value_or(Tweaks{})}; - if (effective_tweaks.assume_bundled) { - sourcemeta::core::SchemaFrame frame{ - sourcemeta::core::SchemaFrame::Mode::References}; - frame.analyse(schema, walker, resolver, default_dialect, default_id); - return compile(schema, walker, resolver, compiler, frame, mode, - default_dialect, default_id, tweaks); - } else { - // Make sure the input schema is bundled, otherwise we won't be able to - // resolve remote references here - const sourcemeta::core::JSON result{sourcemeta::core::bundle( - schema, walker, resolver, default_dialect, default_id)}; - - sourcemeta::core::SchemaFrame frame{ - sourcemeta::core::SchemaFrame::Mode::References}; - frame.analyse(result, walker, resolver, default_dialect, default_id); - return compile(result, walker, resolver, compiler, frame, mode, - default_dialect, default_id, tweaks); - } + // Make sure the input schema is bundled, otherwise we won't be able to + // resolve remote references here + const sourcemeta::core::JSON result{sourcemeta::core::bundle( + schema, walker, resolver, default_dialect, default_id)}; + + sourcemeta::core::SchemaFrame frame{ + sourcemeta::core::SchemaFrame::Mode::References}; + frame.analyse(result, walker, resolver, default_dialect, default_id); + return compile(result, walker, resolver, compiler, frame, + entrypoint.empty() ? frame.root() : entrypoint, mode, tweaks); } auto compile(const Context &context, const SchemaContext &schema_context, diff --git a/vendor/blaze/src/compiler/include/sourcemeta/blaze/compiler.h b/vendor/blaze/src/compiler/include/sourcemeta/blaze/compiler.h index 04c2ae46..81343995 100644 --- a/vendor/blaze/src/compiler/include/sourcemeta/blaze/compiler.h +++ b/vendor/blaze/src/compiler/include/sourcemeta/blaze/compiler.h @@ -94,9 +94,6 @@ struct Tweaks { bool properties_reorder{true}; /// Inline jump targets with fewer instructions than this threshold std::size_t target_inline_threshold{50}; - /// Assume the schema is already bundled with no pending unresolved external - /// references - bool assume_bundled{false}; }; /// @ingroup compiler @@ -169,7 +166,9 @@ compile(const sourcemeta::core::JSON &schema, const sourcemeta::core::SchemaWalker &walker, const sourcemeta::core::SchemaResolver &resolver, const Compiler &compiler, const Mode mode = Mode::FastValidation, - std::string_view default_dialect = "", std::string_view default_id = "", + const std::string_view default_dialect = "", + const std::string_view default_id = "", + const std::string_view entrypoint = "", const std::optional &tweaks = std::nullopt) -> Template; /// @ingroup compiler @@ -181,14 +180,13 @@ compile(const sourcemeta::core::JSON &schema, /// behavior. /// /// Don't use this function unless you know what you are doing. -auto SOURCEMETA_BLAZE_COMPILER_EXPORT -compile(const sourcemeta::core::JSON &schema, - const sourcemeta::core::SchemaWalker &walker, - const sourcemeta::core::SchemaResolver &resolver, - const Compiler &compiler, const sourcemeta::core::SchemaFrame &frame, - const Mode mode = Mode::FastValidation, - std::string_view default_dialect = "", std::string_view default_id = "", - const std::optional &tweaks = std::nullopt) -> Template; +auto SOURCEMETA_BLAZE_COMPILER_EXPORT compile( + const sourcemeta::core::JSON &schema, + const sourcemeta::core::SchemaWalker &walker, + const sourcemeta::core::SchemaResolver &resolver, const Compiler &compiler, + const sourcemeta::core::SchemaFrame &frame, + const std::string_view entrypoint, const Mode mode = Mode::FastValidation, + const std::optional &tweaks = std::nullopt) -> Template; /// @ingroup compiler /// diff --git a/vendor/blaze/src/compiler/include/sourcemeta/blaze/compiler_error.h b/vendor/blaze/src/compiler/include/sourcemeta/blaze/compiler_error.h index 045c2212..63006366 100644 --- a/vendor/blaze/src/compiler/include/sourcemeta/blaze/compiler_error.h +++ b/vendor/blaze/src/compiler/include/sourcemeta/blaze/compiler_error.h @@ -78,6 +78,28 @@ class SOURCEMETA_BLAZE_COMPILER_EXPORT CompilerReferenceTargetNotSchemaError sourcemeta::core::Pointer schema_location_; }; +/// @ingroup jsonschema +/// An error that represents an invalid compilation entrypoint +class SOURCEMETA_BLAZE_COMPILER_EXPORT CompilerInvalidEntryPoint + : public std::exception { +public: + CompilerInvalidEntryPoint(const std::string_view entrypoint, + const std::string_view message) + : identifier_{entrypoint}, message_{message} {} + + [[nodiscard]] auto what() const noexcept -> const char * override { + return this->message_.c_str(); + } + + [[nodiscard]] auto identifier() const noexcept -> const std::string & { + return this->identifier_; + } + +private: + std::string identifier_; + std::string message_; +}; + #if defined(_MSC_VER) #pragma warning(default : 4251 4275) #endif diff --git a/vendor/blaze/src/compiler/unevaluated.cc b/vendor/blaze/src/compiler/unevaluated.cc index 37de5c88..4ef45de3 100644 --- a/vendor/blaze/src/compiler/unevaluated.cc +++ b/vendor/blaze/src/compiler/unevaluated.cc @@ -7,6 +7,9 @@ using namespace sourcemeta::core; using namespace sourcemeta::blaze; using Known = Vocabularies::Known; +static const std::string UNEVALUATED_PROPERTIES{"unevaluatedProperties"}; +static const std::string UNEVALUATED_ITEMS{"unevaluatedItems"}; + auto find_adjacent_dependencies( const JSON::String ¤t, const JSON &schema, const SchemaFrame &frame, const SchemaWalker &walker, const SchemaResolver &resolver, @@ -158,52 +161,57 @@ auto unevaluated(const JSON &schema, const SchemaFrame &frame, continue; } + const bool has_unevaluated_properties{ + subschema.defines("unevaluatedProperties")}; + const bool has_unevaluated_items{subschema.defines("unevaluatedItems")}; + if (!has_unevaluated_properties && !has_unevaluated_items) { + continue; + } + const auto subschema_vocabularies{ frame.vocabularies(entry.second, resolver)}; - for (const auto &pair : subschema.as_object()) { - const auto keyword_uri{ - frame.uri(entry.second, make_weak_pointer(pair.first))}; - SchemaUnevaluatedEntry unevaluated; + if (has_unevaluated_properties) { if ((subschema_vocabularies.contains( Known::JSON_Schema_2020_12_Unevaluated) && subschema_vocabularies.contains( - Known::JSON_Schema_2020_12_Applicator)) && - // NOLINTNEXTLINE(bugprone-branch-clone) - pair.first == "unevaluatedProperties") { + Known::JSON_Schema_2020_12_Applicator)) || + subschema_vocabularies.contains( + Known::JSON_Schema_2019_09_Applicator)) { + SchemaUnevaluatedEntry unevaluated; find_adjacent_dependencies( - pair.first, schema, frame, walker, resolver, + "unevaluatedProperties", schema, frame, walker, resolver, {"properties", "patternProperties", "additionalProperties", "unevaluatedProperties"}, entry.second, entry.second, true, unevaluated); - result.emplace(keyword_uri, std::move(unevaluated)); - } else if ((subschema_vocabularies.contains( - Known::JSON_Schema_2020_12_Unevaluated) && - subschema_vocabularies.contains( - Known::JSON_Schema_2020_12_Applicator)) && - pair.first == "unevaluatedItems") { + result.emplace( + frame.uri(entry.second, make_weak_pointer(UNEVALUATED_PROPERTIES)), + std::move(unevaluated)); + } + } + + if (has_unevaluated_items) { + SchemaUnevaluatedEntry unevaluated; + if (subschema_vocabularies.contains( + Known::JSON_Schema_2020_12_Unevaluated) && + subschema_vocabularies.contains( + Known::JSON_Schema_2020_12_Applicator)) { find_adjacent_dependencies( - pair.first, schema, frame, walker, resolver, + "unevaluatedItems", schema, frame, walker, resolver, {"prefixItems", "items", "contains", "unevaluatedItems"}, entry.second, entry.second, true, unevaluated); - result.emplace(keyword_uri, std::move(unevaluated)); - } else if (subschema_vocabularies.contains( - Known::JSON_Schema_2019_09_Applicator) && - pair.first == "unevaluatedProperties") { - find_adjacent_dependencies( - pair.first, schema, frame, walker, resolver, - {"properties", "patternProperties", "additionalProperties", - "unevaluatedProperties"}, - entry.second, entry.second, true, unevaluated); - result.emplace(keyword_uri, std::move(unevaluated)); + result.emplace( + frame.uri(entry.second, make_weak_pointer(UNEVALUATED_ITEMS)), + std::move(unevaluated)); } else if (subschema_vocabularies.contains( - Known::JSON_Schema_2019_09_Applicator) && - pair.first == "unevaluatedItems") { + Known::JSON_Schema_2019_09_Applicator)) { find_adjacent_dependencies( - pair.first, schema, frame, walker, resolver, + "unevaluatedItems", schema, frame, walker, resolver, {"items", "additionalItems", "unevaluatedItems"}, entry.second, entry.second, true, unevaluated); - result.emplace(keyword_uri, std::move(unevaluated)); + result.emplace( + frame.uri(entry.second, make_weak_pointer(UNEVALUATED_ITEMS)), + std::move(unevaluated)); } } } diff --git a/vendor/blaze/src/linter/include/sourcemeta/blaze/linter.h b/vendor/blaze/src/linter/include/sourcemeta/blaze/linter.h index bb7227a9..c9613379 100644 --- a/vendor/blaze/src/linter/include/sourcemeta/blaze/linter.h +++ b/vendor/blaze/src/linter/include/sourcemeta/blaze/linter.h @@ -6,6 +6,7 @@ #endif #include +#include #include #include // std::true_type @@ -51,6 +52,7 @@ class SOURCEMETA_BLAZE_LINTER_EXPORT ValidExamples final #pragma warning(disable : 4251) #endif const Compiler compiler_; + mutable Evaluator evaluator_; #if defined(_MSC_VER) #pragma warning(default : 4251) #endif @@ -86,6 +88,7 @@ class SOURCEMETA_BLAZE_LINTER_EXPORT ValidDefault final #pragma warning(disable : 4251) #endif const Compiler compiler_; + mutable Evaluator evaluator_; #if defined(_MSC_VER) #pragma warning(default : 4251) #endif diff --git a/vendor/blaze/src/linter/valid_default.cc b/vendor/blaze/src/linter/valid_default.cc index 2b922566..662b4a3f 100644 --- a/vendor/blaze/src/linter/valid_default.cc +++ b/vendor/blaze/src/linter/valid_default.cc @@ -45,31 +45,52 @@ auto ValidDefault::condition( } } + const auto &instance{schema.at("default")}; + + if (frame.standalone()) { + const auto base{frame.uri(location.pointer)}; + assert(base.has_value()); + const auto schema_template{compile(root, walker, resolver, this->compiler_, + frame, base.value().get(), + Mode::Exhaustive)}; + SimpleOutput output{instance}; + const auto result{ + this->evaluator_.validate(schema_template, instance, std::ref(output))}; + if (result) { + return false; + } + + std::ostringstream message; + for (const auto &entry : output) { + message << entry.message << "\n"; + message << " at instance location \""; + sourcemeta::core::stringify(entry.instance_location, message); + message << "\"\n"; + message << " at evaluate path \""; + sourcemeta::core::stringify(entry.evaluate_path, message); + message << "\"\n"; + } + + return {{{"default"}}, std::move(message).str()}; + } + const auto &root_base_dialect{ frame.traverse(frame.root()).value_or(location).get().base_dialect}; std::string_view default_id{location.base}; if (!sourcemeta::core::identify(root, root_base_dialect).empty() || default_id.empty()) { - // We want to only set a default identifier if the root schema does not - // have an explicit identifier. Otherwise, we can get into corner case - // when wrapping the schema default_id = ""; } sourcemeta::core::WeakPointer base; const auto subschema{ sourcemeta::core::wrap(root, frame, location, resolver, base)}; - // To avoid bundling twice in vain - Tweaks tweaks{.assume_bundled = frame.standalone()}; const auto schema_template{compile(subschema, walker, resolver, this->compiler_, Mode::Exhaustive, - location.dialect, default_id, tweaks)}; - - const auto &instance{schema.at("default")}; - Evaluator evaluator; + location.dialect, default_id)}; SimpleOutput output{instance, base}; const auto result{ - evaluator.validate(schema_template, instance, std::ref(output))}; + this->evaluator_.validate(schema_template, instance, std::ref(output))}; if (result) { return false; } diff --git a/vendor/blaze/src/linter/valid_examples.cc b/vendor/blaze/src/linter/valid_examples.cc index 4723ffa0..d2b9c7eb 100644 --- a/vendor/blaze/src/linter/valid_examples.cc +++ b/vendor/blaze/src/linter/valid_examples.cc @@ -49,32 +49,62 @@ auto ValidExamples::condition( } } + std::size_t cursor{0}; + + if (frame.standalone()) { + const auto base{frame.uri(location.pointer)}; + assert(base.has_value()); + const auto schema_template{compile(root, walker, resolver, this->compiler_, + frame, base.value().get(), + Mode::Exhaustive)}; + + for (const auto &example : schema.at("examples").as_array()) { + SimpleOutput output{example}; + const auto result{this->evaluator_.validate(schema_template, example, + std::ref(output))}; + if (!result) { + std::ostringstream message; + message << "Invalid example instance at index " << cursor << "\n"; + for (const auto &entry : output) { + message << " " << entry.message << "\n"; + message << " " + << " at instance location \""; + sourcemeta::core::stringify(entry.instance_location, message); + message << "\"\n"; + message << " " + << " at evaluate path \""; + sourcemeta::core::stringify(entry.evaluate_path, message); + message << "\"\n"; + } + + return {{{"examples", cursor}}, std::move(message).str()}; + } + + cursor += 1; + } + + return false; + } + const auto &root_base_dialect{ frame.traverse(frame.root()).value_or(location).get().base_dialect}; std::string_view default_id{location.base}; if (!sourcemeta::core::identify(root, root_base_dialect).empty() || default_id.empty()) { - // We want to only set a default identifier if the root schema does not - // have an explicit identifier. Otherwise, we can get into corner case - // when wrapping the schema default_id = ""; } sourcemeta::core::WeakPointer base; const auto subschema{ sourcemeta::core::wrap(root, frame, location, resolver, base)}; - // To avoid bundling twice in vain - Tweaks tweaks{.assume_bundled = frame.standalone()}; const auto schema_template{compile(subschema, walker, resolver, this->compiler_, Mode::Exhaustive, - location.dialect, default_id, tweaks)}; + location.dialect, default_id)}; - Evaluator evaluator; - std::size_t cursor{0}; for (const auto &example : schema.at("examples").as_array()) { SimpleOutput output{example, base}; const auto result{ - evaluator.validate(schema_template, example, std::ref(output))}; + this->evaluator_.validate(schema_template, example, std::ref(output))}; if (!result) { std::ostringstream message; message << "Invalid example instance at index " << cursor << "\n"; diff --git a/vendor/blaze/src/test/test_parser.cc b/vendor/blaze/src/test/test_parser.cc index 22ea86b8..92505aa6 100644 --- a/vendor/blaze/src/test/test_parser.cc +++ b/vendor/blaze/src/test/test_parser.cc @@ -134,10 +134,10 @@ auto TestSuite::parse(const sourcemeta::core::JSON &document, try { test_suite.schema_fast = compile(target_schema, walker, schema_resolver, compiler, - Mode::FastValidation, default_dialect, default_id, tweaks); + Mode::FastValidation, default_dialect, default_id, "", tweaks); test_suite.schema_exhaustive = compile(target_schema, walker, schema_resolver, compiler, - Mode::Exhaustive, default_dialect, default_id, tweaks); + Mode::Exhaustive, default_dialect, default_id, "", tweaks); } catch (const sourcemeta::core::SchemaReferenceError &error) { if (error.location() == sourcemeta::core::Pointer{"$ref"} && error.identifier() == test_suite.target) { diff --git a/vendor/codegen/src/ir/ir.cc b/vendor/codegen/src/ir/ir.cc index 821d6a9f..faffeb5e 100644 --- a/vendor/codegen/src/ir/ir.cc +++ b/vendor/codegen/src/ir/ir.cc @@ -30,7 +30,8 @@ auto compile(const sourcemeta::core::JSON &input, sourcemeta::core::AlterSchemaMode::Canonicalizer); [[maybe_unused]] const auto canonicalized{canonicalizer.apply( schema, walker, resolver, - [](const auto &, const auto, const auto, const auto &) { assert(false); }, + [](const auto &, const auto, const auto, const auto &, + [[maybe_unused]] const auto applied) { assert(applied); }, default_dialect, default_id)}; assert(canonicalized.first); diff --git a/vendor/core/src/core/jsonschema/frame.cc b/vendor/core/src/core/jsonschema/frame.cc index 40b351c6..72ef00cd 100644 --- a/vendor/core/src/core/jsonschema/frame.cc +++ b/vendor/core/src/core/jsonschema/frame.cc @@ -1394,9 +1394,14 @@ auto SchemaFrame::empty() const noexcept -> bool { } auto SchemaFrame::reset() -> void { - // Note that order of removal is important to avoid undefined behaviour + this->pointers_with_non_orphan_.clear(); this->pointer_to_location_.clear(); this->reachability_.clear(); + this->references_by_destination_.clear(); + this->location_members_children_.clear(); + this->descendants_by_pointer_.clear(); + this->potential_sources_by_location_.clear(); + this->reachability_graph_.clear(); this->root_.clear(); this->locations_.clear(); this->references_.clear(); @@ -1415,73 +1420,135 @@ auto SchemaFrame::populate_pointer_to_location() const -> void { } } -// TODO: Find a way to split or simplify this monster while preserving -// its performance? -auto SchemaFrame::populate_reachability(const SchemaWalker &walker, - const SchemaResolver &resolver) const - -> void { - if (!this->reachability_.empty()) { +auto SchemaFrame::populate_location_members( + const SchemaWalker &walker, const SchemaResolver &resolver) const -> void { + if (!this->location_members_children_.empty()) { return; } - // --------------------------------------------------------------------------- - // (1) Find all unreachable pointers - // --------------------------------------------------------------------------- + this->populate_pointer_to_location(); + + for (const auto &entry : this->locations_) { + if (entry.second.type != LocationType::Subschema) { + continue; + } + if (!entry.second.parent.has_value()) { + continue; + } + const auto &parent_pointer{entry.second.parent.value()}; + const auto relative{entry.second.pointer.slice(parent_pointer.size())}; + if (relative.empty() || !relative.at(0).is_property()) { + continue; + } + const auto parent_location{this->traverse(parent_pointer)}; + if (!parent_location.has_value()) { + continue; + } + const auto vocabs{this->vocabularies(parent_location->get(), resolver)}; + const auto &keyword_result{walker(relative.at(0).to_property(), vocabs)}; + if (keyword_result.type == SchemaKeywordType::LocationMembers) { + this->location_members_children_.insert(std::cref(entry.second.pointer)); + } + } +} + +auto SchemaFrame::populate_descendants() const -> void { + if (!this->descendants_by_pointer_.empty()) { + return; + } - std::vector> unreachable_pointers; + this->populate_pointer_to_location(); - if (this->pointer_to_location_.empty()) { - std::unordered_set, - WeakPointer::Hasher, WeakPointer::Comparator> - has_non_pointer_location; - std::unordered_set, - WeakPointer::Hasher, WeakPointer::Comparator> - has_non_orphan; + for (const auto &entry : this->locations_) { + if (entry.second.type == LocationType::Pointer) { + continue; + } - for (const auto &entry : this->locations_) { - auto [iterator, inserted] = this->pointer_to_location_.try_emplace( - std::cref(entry.second.pointer), std::vector{}); - iterator->second.push_back(&entry.second); - if (entry.second.type != LocationType::Pointer) { - has_non_pointer_location.insert(iterator->first); - if (!entry.second.orphan) { - has_non_orphan.insert(iterator->first); + const auto &pointer{entry.second.pointer}; + const auto *location{&entry.second}; + + WeakPointer prefix; + for (std::size_t index = 0; index <= pointer.size(); ++index) { + auto prefix_iter = this->pointer_to_location_.find(std::cref(prefix)); + if (prefix_iter != this->pointer_to_location_.end() && + !prefix_iter->second.empty()) { + const auto &key_pointer{prefix_iter->second.front()->pointer}; + this->descendants_by_pointer_[std::cref(key_pointer)].push_back( + location); + } + if (index < pointer.size()) { + const auto &token{pointer.at(index)}; + if (token.is_property()) { + prefix.emplace_back(token.to_property(), token.property_hash()); + } else { + prefix.push_back(token.to_index()); } } } + } +} - for (const auto &pointer_reference : has_non_pointer_location) { - const bool is_reachable = has_non_orphan.contains(pointer_reference); - this->reachability_.emplace(pointer_reference, is_reachable); - if (!is_reachable) { - unreachable_pointers.push_back(pointer_reference); - } +auto SchemaFrame::populate_potential_sources( + const SchemaWalker &walker, const SchemaResolver &resolver) const -> void { + if (!this->potential_sources_by_location_.empty()) { + return; + } + + this->populate_reference_graph(); + this->populate_location_members(walker, resolver); + + for (const auto &entry : this->locations_) { + if (entry.second.type == LocationType::Pointer) { + continue; } - } else { - for (const auto &[pointer_reference, locations] : - this->pointer_to_location_) { - const auto has_non_pointer{ - std::ranges::any_of(locations, [](const Location *location) { - return location->type != LocationType::Pointer; - })}; - if (!has_non_pointer) { - continue; + + const auto &pointer{entry.second.pointer}; + const auto *location{&entry.second}; + std::vector sources; + + WeakPointer ancestor = pointer; + bool first_iteration{true}; + while (first_iteration || !ancestor.empty()) { + auto destination_iterator = + this->references_by_destination_.find(std::cref(ancestor)); + if (destination_iterator != this->references_by_destination_.end()) { + bool crosses{false}; + if (ancestor != pointer) { + for (const auto &boundary_ref : this->location_members_children_) { + const auto &boundary{boundary_ref.get()}; + if (pointer.starts_with(boundary) && + !ancestor.starts_with(boundary)) { + crosses = true; + break; + } + } + } + + for (const auto *source_pointer : destination_iterator->second) { + sources.push_back( + PotentialSource{.source_pointer = source_pointer, + .source_parent = source_pointer->initial(), + .crosses = crosses}); + } } - const auto any_non_orphan{ - std::ranges::any_of(locations, [](const Location *location) { - return location->type != LocationType::Pointer && !location->orphan; - })}; - this->reachability_.emplace(pointer_reference, any_non_orphan); - if (!any_non_orphan) { - unreachable_pointers.push_back(pointer_reference); + if (ancestor.empty()) { + break; } + ancestor = ancestor.initial(); + first_iteration = false; + } + + if (!sources.empty()) { + this->potential_sources_by_location_[location] = std::move(sources); } } +} - // --------------------------------------------------------------------------- - // (2) Build a reverse mapping from reference destinations to their sources - // --------------------------------------------------------------------------- +auto SchemaFrame::populate_reference_graph() const -> void { + if (!this->references_by_destination_.empty()) { + return; + } std::unordered_map> dynamic_anchors_by_fragment; @@ -1531,158 +1598,166 @@ auto SchemaFrame::populate_reachability(const SchemaWalker &walker, } } - std::unordered_map, - std::vector, WeakPointer::Hasher, - WeakPointer::Comparator> - references_by_destination; for (const auto &[source, destination] : reference_destinations) { - references_by_destination[std::cref(*destination)].push_back(source); + this->references_by_destination_[std::cref(*destination)].push_back(source); } +} - // --------------------------------------------------------------------------- - // (3) Precompute which references could make each orphan reachable - // --------------------------------------------------------------------------- +auto SchemaFrame::populate_reachability_graph( + const SchemaWalker &walker, const SchemaResolver &resolver) const -> void { + if (!this->reachability_graph_.empty()) { + return; + } - struct PotentialSource { - const WeakPointer *source_pointer; - bool crosses; - }; - struct PotentialReach { - std::reference_wrapper pointer; - std::vector potential_sources; - }; - std::vector unreachable_with_sources; - unreachable_with_sources.reserve(unreachable_pointers.size()); + this->populate_pointer_to_location(); + this->populate_location_members(walker, resolver); + this->populate_reference_graph(); - std::unordered_map vocabularies_cache; + for (const auto &entry : this->locations_) { + if (entry.second.pointer.empty()) { + continue; + } - for (const auto &pointer_reference : unreachable_pointers) { - const auto &pointer{pointer_reference.get()}; - PotentialReach entry{.pointer = pointer_reference, .potential_sources = {}}; + const auto parent_pointer{entry.second.pointer.initial()}; + auto parent_iterator = + this->pointer_to_location_.find(std::cref(parent_pointer)); + if (parent_iterator == this->pointer_to_location_.end()) { + continue; + } - WeakPointer ancestor = pointer; - while (!ancestor.empty()) { - auto destination_iterator = - references_by_destination.find(std::cref(ancestor)); - if (destination_iterator != references_by_destination.end()) { - bool crosses{false}; - if (ancestor != pointer) { - auto check_location{this->traverse(pointer)}; - while (check_location.has_value()) { - const auto &location{check_location->get()}; - if (location.pointer == ancestor) { - break; - } + for (const Location *parent_location : parent_iterator->second) { + this->reachability_graph_[parent_location].push_back( + ReachabilityEdge{.target = &entry.second, + .orphan_context_only = entry.second.orphan, + .is_reference = false}); + } + } - if (!location.parent.has_value()) { - break; - } + for (const auto &[destination_reference, sources] : + this->references_by_destination_) { + auto destination_locations_iterator = + this->pointer_to_location_.find(destination_reference); + if (destination_locations_iterator == this->pointer_to_location_.end()) { + continue; + } - const auto parent_location{this->traverse(location.parent.value())}; - if (!parent_location.has_value()) { - break; - } + const Location *destination_location{nullptr}; + for (const auto *location : destination_locations_iterator->second) { + if (location->type != LocationType::Pointer) { + destination_location = location; + break; + } + } - const auto relative{ - location.pointer.slice(location.parent.value().size())}; - if (!relative.empty() && relative.at(0).is_property()) { - const auto &parent_loc{parent_location->get()}; - auto vocab_iterator = - vocabularies_cache.find(parent_loc.base_dialect); - if (vocab_iterator == vocabularies_cache.end()) { - auto [inserted_iterator, inserted] = vocabularies_cache.emplace( - parent_loc.base_dialect, - this->vocabularies(parent_loc, resolver)); - vocab_iterator = inserted_iterator; - } + if (!destination_location && + !destination_locations_iterator->second.empty()) { + destination_location = destination_locations_iterator->second.front(); + } - const auto &keyword_result{ - walker(relative.at(0).to_property(), vocab_iterator->second)}; - if (keyword_result.type == SchemaKeywordType::LocationMembers) { - crosses = true; - break; - } - } + if (!destination_location) { + continue; + } - check_location = parent_location; - } - } + for (const auto *source_pointer : sources) { + if (source_pointer->empty()) { + continue; + } - for (const auto *source_pointer : destination_iterator->second) { - entry.potential_sources.push_back(PotentialSource{ - .source_pointer = source_pointer, .crosses = crosses}); - } + const auto source_parent_pointer{source_pointer->initial()}; + auto source_parent_iterator = + this->pointer_to_location_.find(std::cref(source_parent_pointer)); + if (source_parent_iterator == this->pointer_to_location_.end()) { + continue; } - ancestor = ancestor.initial(); - } - if (!entry.potential_sources.empty()) { - unreachable_with_sources.push_back(std::move(entry)); + for (const Location *source_parent_location : + source_parent_iterator->second) { + this->reachability_graph_[source_parent_location].push_back( + ReachabilityEdge{.target = destination_location, + .orphan_context_only = false, + .is_reference = true}); + } } } +} - std::ranges::sort(unreachable_with_sources, [](const PotentialReach &left, - const PotentialReach &right) { - return left.pointer.get().size() < right.pointer.get().size(); - }); +auto SchemaFrame::populate_reachability(const Location &base, + const SchemaWalker &walker, + const SchemaResolver &resolver) const + -> const ReachabilityCache & { + const ReachabilityKey key{.pointer = &base.pointer, .orphan = base.orphan}; + auto cache_iterator = this->reachability_.find(key); + if (cache_iterator != this->reachability_.end()) { + return cache_iterator->second; + } - // --------------------------------------------------------------------------- - // (4) Propagate reachability through references using fixpoint iteration - // --------------------------------------------------------------------------- + auto &cache = this->reachability_[key]; + this->populate_reachability_graph(walker, resolver); + const Location *base_location{&base}; + std::vector queue; + std::unordered_set visited; + + auto mark_pointer_reachable = [this, &cache](const WeakPointer &pointer) { + auto locations_iterator = + this->pointer_to_location_.find(std::cref(pointer)); + if (locations_iterator != this->pointer_to_location_.end()) { + for (const auto *location : locations_iterator->second) { + if (location->type != LocationType::Pointer) { + cache.emplace(std::cref(location->pointer), true); + } + } + } + }; - bool changed{true}; - while (changed) { - changed = false; + queue.push_back(base_location); + visited.insert(base_location); + mark_pointer_reachable(base_location->pointer); - auto write_iterator = unreachable_with_sources.begin(); - for (auto read_iterator = unreachable_with_sources.begin(); - read_iterator != unreachable_with_sources.end(); ++read_iterator) { - bool became_reachable = false; + std::size_t queue_index{0}; + while (queue_index < queue.size()) { + const Location *current = queue[queue_index++]; - for (const auto &potential_source : read_iterator->potential_sources) { - if (potential_source.crosses) { - continue; - } + auto edges_iterator = this->reachability_graph_.find(current); + if (edges_iterator == this->reachability_graph_.end()) { + continue; + } - const auto &source_parent{potential_source.source_pointer->initial()}; - bool source_parent_reachable{source_parent.empty()}; - if (!source_parent_reachable) { - const auto reachability_iterator{ - this->reachability_.find(std::cref(source_parent))}; - source_parent_reachable = - reachability_iterator != this->reachability_.end() && - reachability_iterator->second; - } + for (const auto &edge : edges_iterator->second) { + if (visited.contains(edge.target)) { + continue; + } - if (source_parent_reachable) { - became_reachable = true; - break; - } + if (edge.orphan_context_only && !base.orphan && !current->orphan) { + continue; } - if (became_reachable) { - this->reachability_[read_iterator->pointer] = true; - changed = true; - } else { - if (write_iterator != read_iterator) { - *write_iterator = std::move(*read_iterator); + if (!edge.is_reference && edge.orphan_context_only) { + auto target_iterator = this->location_members_children_.find( + std::cref(edge.target->pointer)); + if (target_iterator != this->location_members_children_.end()) { + const auto keyword_path{edge.target->pointer.initial()}; + if (keyword_path.starts_with(current->pointer)) { + continue; + } } - ++write_iterator; } + + visited.insert(edge.target); + queue.push_back(edge.target); + mark_pointer_reachable(edge.target->pointer); } - unreachable_with_sources.erase(write_iterator, - unreachable_with_sources.end()); } + + return cache; } -auto SchemaFrame::is_reachable(const Location &location, +auto SchemaFrame::is_reachable(const Location &base, const Location &location, const SchemaWalker &walker, const SchemaResolver &resolver) const -> bool { assert(location.type != LocationType::Pointer); - this->populate_reachability(walker, resolver); - const auto iterator{this->reachability_.find(std::cref(location.pointer))}; - assert(iterator != this->reachability_.end()); - return iterator->second; + const auto &cache{this->populate_reachability(base, walker, resolver)}; + const auto iterator{cache.find(std::cref(location.pointer))}; + return iterator != cache.end() && iterator->second; } } // namespace sourcemeta::core diff --git a/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_frame.h b/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_frame.h index 522dbfa0..f18a5f1c 100644 --- a/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_frame.h +++ b/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_frame.h @@ -242,15 +242,12 @@ class SOURCEMETA_CORE_JSONSCHEMA_EXPORT SchemaFrame { auto reset() -> void; /// Determines if a location could be evaluated during validation - [[nodiscard]] auto is_reachable(const Location &location, + [[nodiscard]] auto is_reachable(const Location &base, + const Location &location, const SchemaWalker &walker, const SchemaResolver &resolver) const -> bool; private: - auto populate_pointer_to_location() const -> void; - auto populate_reachability(const SchemaWalker &walker, - const SchemaResolver &resolver) const -> void; - Mode mode_; // Exporting symbols that depends on the standard C++ library is considered // safe. @@ -265,10 +262,68 @@ class SOURCEMETA_CORE_JSONSCHEMA_EXPORT SchemaFrame { std::vector, WeakPointer::Hasher, WeakPointer::Comparator> pointer_to_location_; - mutable std::unordered_map, bool, + mutable std::unordered_set, WeakPointer::Hasher, WeakPointer::Comparator> + pointers_with_non_orphan_; + using ReachabilityCache = + std::unordered_map, bool, + WeakPointer::Hasher, WeakPointer::Comparator>; + struct ReachabilityKey { + const WeakPointer *pointer; + bool orphan; + auto operator==(const ReachabilityKey &other) const noexcept -> bool { + return this->pointer == other.pointer && this->orphan == other.orphan; + } + }; + struct ReachabilityKeyHasher { + auto operator()(const ReachabilityKey &key) const noexcept -> std::size_t { + return std::hash{}(key.pointer) ^ + (std::hash{}(key.orphan) << 1); + } + }; + mutable std::unordered_map reachability_; + mutable std::unordered_map, + std::vector, + WeakPointer::Hasher, WeakPointer::Comparator> + references_by_destination_; + mutable std::unordered_set, + WeakPointer::Hasher, WeakPointer::Comparator> + location_members_children_; + mutable std::unordered_map, + std::vector, WeakPointer::Hasher, + WeakPointer::Comparator> + descendants_by_pointer_; + struct PotentialSource { + const WeakPointer *source_pointer; + WeakPointer source_parent; + bool crosses; + }; + mutable std::unordered_map> + potential_sources_by_location_; + struct ReachabilityEdge { + const Location *target; + bool orphan_context_only; + bool is_reference; + }; + mutable std::unordered_map> + reachability_graph_; bool standalone_{false}; + + auto populate_pointer_to_location() const -> void; + auto populate_reference_graph() const -> void; + auto populate_location_members(const SchemaWalker &walker, + const SchemaResolver &resolver) const -> void; + auto populate_descendants() const -> void; + auto populate_potential_sources(const SchemaWalker &walker, + const SchemaResolver &resolver) const -> void; + auto populate_reachability_graph(const SchemaWalker &walker, + const SchemaResolver &resolver) const + -> void; + auto populate_reachability(const Location &base, const SchemaWalker &walker, + const SchemaResolver &resolver) const + -> const ReachabilityCache &; #if defined(_MSC_VER) #pragma warning(default : 4251 4275) #endif diff --git a/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_transform.h b/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_transform.h index 55ff68d4..f2b9f700 100644 --- a/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_transform.h +++ b/vendor/core/src/core/jsonschema/include/sourcemeta/core/jsonschema_transform.h @@ -253,9 +253,10 @@ class SOURCEMETA_CORE_JSONSCHEMA_EXPORT SchemaTransformer { /// - The name of the rule /// - The message of the rule /// - The rule evaluation result - using Callback = std::function; + /// - Whether the rule is mutable (on check) or was mutated (on apply) + using Callback = std::function; /// Apply the bundle of rules to a schema [[nodiscard]] auto diff --git a/vendor/core/src/core/jsonschema/transformer.cc b/vendor/core/src/core/jsonschema/transformer.cc index 2ff1010e..e7ba51f7 100644 --- a/vendor/core/src/core/jsonschema/transformer.cc +++ b/vendor/core/src/core/jsonschema/transformer.cc @@ -87,7 +87,8 @@ auto check_rules( exclude_keyword)}; if (outcome.applies) { subschema_failed = true; - callback(entry_pointer, rule->name(), rule->message(), outcome); + callback(entry_pointer, rule->name(), rule->message(), outcome, + mutates); } } @@ -273,6 +274,7 @@ auto SchemaTransformer::apply(JSON &schema, const SchemaWalker &walker, } rule->transform(current, outcome); + callback(entry_pointer, rule->name(), rule->message(), outcome, true); applied = true; diff --git a/vendor/core/src/extension/alterschema/common/orphan_definitions.h b/vendor/core/src/extension/alterschema/common/orphan_definitions.h index 047156fe..a59c8693 100644 --- a/vendor/core/src/extension/alterschema/common/orphan_definitions.h +++ b/vendor/core/src/extension/alterschema/common/orphan_definitions.h @@ -30,11 +30,14 @@ class OrphanDefinitions final : public SchemaTransformRule { schema.defines("definitions")}; ONLY_CONTINUE_IF(has_defs || has_definitions); + const auto base{frame.traverse(frame.root())}; + ONLY_CONTINUE_IF(base.has_value()); + std::vector orphans; - collect_orphans(frame, walker, resolver, location.pointer, schema, "$defs", - has_defs, orphans); - collect_orphans(frame, walker, resolver, location.pointer, schema, - "definitions", has_definitions, orphans); + collect_orphans(frame, base->get(), walker, resolver, location.pointer, + schema, "$defs", has_defs, orphans); + collect_orphans(frame, base->get(), walker, resolver, location.pointer, + schema, "definitions", has_definitions, orphans); ONLY_CONTINUE_IF(!orphans.empty()); return APPLIES_TO_POINTERS(std::move(orphans)); @@ -61,6 +64,7 @@ class OrphanDefinitions final : public SchemaTransformRule { private: static auto has_reachable_reference_through( const sourcemeta::core::SchemaFrame &frame, + const sourcemeta::core::SchemaFrame::Location &base, const sourcemeta::core::SchemaWalker &walker, const sourcemeta::core::SchemaResolver &resolver, const WeakPointer &pointer) -> bool { @@ -83,7 +87,7 @@ class OrphanDefinitions final : public SchemaTransformRule { source_pointer.initial(), sourcemeta::core::SchemaFrame::LocationType::Subschema)}; if (source_location.has_value() && - frame.is_reachable(source_location->get(), walker, resolver)) { + frame.is_reachable(base, source_location->get(), walker, resolver)) { return true; } } @@ -91,13 +95,14 @@ class OrphanDefinitions final : public SchemaTransformRule { return false; } - static auto collect_orphans(const sourcemeta::core::SchemaFrame &frame, - const sourcemeta::core::SchemaWalker &walker, - const sourcemeta::core::SchemaResolver &resolver, - const WeakPointer &prefix, const JSON &schema, - const JSON::String &container, - const bool has_container, - std::vector &orphans) -> void { + static auto + collect_orphans(const sourcemeta::core::SchemaFrame &frame, + const sourcemeta::core::SchemaFrame::Location &base, + const sourcemeta::core::SchemaWalker &walker, + const sourcemeta::core::SchemaResolver &resolver, + const WeakPointer &prefix, const JSON &schema, + const JSON::String &container, const bool has_container, + std::vector &orphans) -> void { if (!has_container || !schema.at(container).is_object()) { return; } @@ -110,8 +115,8 @@ class OrphanDefinitions final : public SchemaTransformRule { absolute_entry_pointer, sourcemeta::core::SchemaFrame::LocationType::Subschema)}; if (entry_location.has_value() && - !frame.is_reachable(entry_location->get(), walker, resolver) && - !has_reachable_reference_through(frame, walker, resolver, + !frame.is_reachable(base, entry_location->get(), walker, resolver) && + !has_reachable_reference_through(frame, base, walker, resolver, absolute_entry_pointer)) { orphans.push_back(Pointer{container, entry.first}); } diff --git a/vendor/jsonbinpack/src/compiler/compiler.cc b/vendor/jsonbinpack/src/compiler/compiler.cc index 9e5b8f36..b951df0a 100644 --- a/vendor/jsonbinpack/src/compiler/compiler.cc +++ b/vendor/jsonbinpack/src/compiler/compiler.cc @@ -12,11 +12,9 @@ static auto transformer_callback_noop(const sourcemeta::core::Pointer &, const std::string_view, const std::string_view, - const sourcemeta::core::SchemaTransformRule::Result &) - -> void { - // This callback should never be called, as all the transformation rules - // we define in this project can indeed be transformed - assert(false); + const sourcemeta::core::SchemaTransformRule::Result &, + [[maybe_unused]] const bool applied) -> void { + assert(applied); } namespace sourcemeta::jsonbinpack { diff --git a/vendor/jsonschema/VERSION b/vendor/jsonschema/VERSION index df249f48..654afc8e 100644 --- a/vendor/jsonschema/VERSION +++ b/vendor/jsonschema/VERSION @@ -1 +1 @@ -14.6.0 +14.7.0 diff --git a/vendor/jsonschema/src/command_canonicalize.cc b/vendor/jsonschema/src/command_canonicalize.cc index ec1db4f8..fd4962af 100644 --- a/vendor/jsonschema/src/command_canonicalize.cc +++ b/vendor/jsonschema/src/command_canonicalize.cc @@ -14,7 +14,8 @@ namespace { auto transformer_callback_noop( const sourcemeta::core::Pointer &, const std::string_view, const std::string_view, - const sourcemeta::core::SchemaTransformRule::Result &) -> void {} + const sourcemeta::core::SchemaTransformRule::Result &, const bool) -> void { +} } // namespace auto sourcemeta::jsonschema::canonicalize( diff --git a/vendor/jsonschema/src/command_compile.cc b/vendor/jsonschema/src/command_compile.cc index 39d017fd..0d1648fb 100644 --- a/vendor/jsonschema/src/command_compile.cc +++ b/vendor/jsonschema/src/command_compile.cc @@ -38,17 +38,41 @@ auto sourcemeta::jsonschema::compile(const sourcemeta::core::Options &options) } const auto fast_mode{options.contains("fast")}; + const auto &custom_resolver{ + resolver(options, options.contains("http"), dialect, configuration)}; + const auto schema_default_id{sourcemeta::jsonschema::default_id(schema_path)}; sourcemeta::blaze::Template schema_template; try { - const auto &custom_resolver{ - resolver(options, options.contains("http"), dialect, configuration)}; - schema_template = sourcemeta::blaze::compile( - schema, sourcemeta::core::schema_walker, custom_resolver, - sourcemeta::blaze::default_schema_compiler, - fast_mode ? sourcemeta::blaze::Mode::FastValidation - : sourcemeta::blaze::Mode::Exhaustive, - dialect, sourcemeta::jsonschema::default_id(schema_path)); + if (options.contains("entrypoint") && !options.at("entrypoint").empty()) { + const sourcemeta::core::JSON bundled{sourcemeta::core::bundle( + schema, sourcemeta::core::schema_walker, custom_resolver, dialect, + schema_default_id)}; + + sourcemeta::core::SchemaFrame frame{ + sourcemeta::core::SchemaFrame::Mode::References}; + frame.analyse(bundled, sourcemeta::core::schema_walker, custom_resolver, + dialect, schema_default_id); + + const auto entrypoint_uri{resolve_entrypoint( + frame, std::string{options.at("entrypoint").front()})}; + + schema_template = sourcemeta::blaze::compile( + bundled, sourcemeta::core::schema_walker, custom_resolver, + sourcemeta::blaze::default_schema_compiler, frame, entrypoint_uri, + fast_mode ? sourcemeta::blaze::Mode::FastValidation + : sourcemeta::blaze::Mode::Exhaustive); + } else { + schema_template = sourcemeta::blaze::compile( + schema, sourcemeta::core::schema_walker, custom_resolver, + sourcemeta::blaze::default_schema_compiler, + fast_mode ? sourcemeta::blaze::Mode::FastValidation + : sourcemeta::blaze::Mode::Exhaustive, + dialect, schema_default_id); + } + } catch (const sourcemeta::blaze::CompilerInvalidEntryPoint &error) { + throw FileError(schema_path, + error); } catch ( const sourcemeta::blaze::CompilerReferenceTargetNotSchemaError &error) { throw FileError( diff --git a/vendor/jsonschema/src/command_lint.cc b/vendor/jsonschema/src/command_lint.cc index 54d77926..56390a23 100644 --- a/vendor/jsonschema/src/command_lint.cc +++ b/vendor/jsonschema/src/command_lint.cc @@ -7,7 +7,7 @@ #include #include // EXIT_FAILURE -#include // std::ofstream +#include // std::ofstream, std::ifstream #include // std::cerr, std::cout #include // std::accumulate #include // std::ostringstream @@ -55,10 +55,25 @@ static auto reindent(const std::string_view &value, static auto get_lint_callback(sourcemeta::core::JSON &errors_array, const sourcemeta::jsonschema::InputJSON &entry, - const bool output_json) -> auto { - return [&entry, &errors_array, - output_json](const auto &pointer, const auto &name, - const auto &message, const auto &result) { + const bool output_json, const bool fixing, + bool &printed_progress) -> auto { + return [&entry, &errors_array, output_json, fixing, &printed_progress]( + const auto &pointer, const auto &name, const auto &message, + const auto &result, const auto applied) { + if (fixing && applied) { + if (!output_json) { + std::cerr << "."; + printed_progress = true; + } + + return; + } + + if (printed_progress) { + std::cerr << "\n"; + printed_progress = false; + } + std::vector locations; if (result.locations.empty()) { locations.emplace_back(); @@ -181,6 +196,18 @@ auto sourcemeta::jsonschema::lint(const sourcemeta::core::Options &options) return; } + const bool format_output{options.contains("format")}; + const bool keep_ordering{options.contains("keep-ordering")}; + + if (format_output && !options.contains("fix")) { + throw OptionConflictError{"The --format option requires --fix to be set"}; + } + + if (keep_ordering && !format_output) { + throw OptionConflictError{ + "The --keep-ordering option requires --format to be set"}; + } + bool result{true}; auto errors_array = sourcemeta::core::JSON::make_array(); std::vector scores; @@ -203,15 +230,20 @@ auto sourcemeta::jsonschema::lint(const sourcemeta::core::Options &options) } auto copy = entry.second; + bool printed_progress{false}; const auto wrapper_result = sourcemeta::jsonschema::try_catch(options, [&]() { try { const auto apply_result = bundle.apply( copy, sourcemeta::core::schema_walker, custom_resolver, - get_lint_callback(errors_array, entry, output_json), dialect, - sourcemeta::jsonschema::default_id(entry.first), + get_lint_callback(errors_array, entry, output_json, true, + printed_progress), + dialect, sourcemeta::jsonschema::default_id(entry.first), EXCLUDE_KEYWORD); + if (printed_progress) { + std::cerr << "\n"; + } scores.emplace_back(apply_result.second); if (!apply_result.first) { return 2; @@ -221,10 +253,18 @@ auto sourcemeta::jsonschema::lint(const sourcemeta::core::Options &options) } catch ( const sourcemeta::core::SchemaTransformRuleProcessedTwiceError &error) { + if (printed_progress) { + std::cerr << "\n"; + } + throw LintAutoFixError{error.what(), entry.first, error.location()}; } catch ( const sourcemeta::core::SchemaBrokenReferenceError &error) { + if (printed_progress) { + std::cerr << "\n"; + } + throw LintAutoFixError{ "Could not autofix the schema without breaking its internal " "references", @@ -232,21 +272,47 @@ auto sourcemeta::jsonschema::lint(const sourcemeta::core::Options &options) } catch ( const sourcemeta::blaze::CompilerReferenceTargetNotSchemaError &error) { + if (printed_progress) { + std::cerr << "\n"; + } + throw FileError< sourcemeta::blaze::CompilerReferenceTargetNotSchemaError>( entry.first, error); } catch (const sourcemeta::core::SchemaKeywordError &error) { + if (printed_progress) { + std::cerr << "\n"; + } + throw FileError(entry.first, error); } catch (const sourcemeta::core::SchemaFrameError &error) { + if (printed_progress) { + std::cerr << "\n"; + } + throw FileError(entry.first, error); } catch (const sourcemeta::core::SchemaUnknownBaseDialectError &) { + if (printed_progress) { + std::cerr << "\n"; + } + throw FileError( entry.first); } catch (const sourcemeta::core::SchemaResolutionError &error) { + if (printed_progress) { + std::cerr << "\n"; + } + throw FileError( entry.first, error); + } catch (...) { + if (printed_progress) { + std::cerr << "\n"; + } + + throw; } }); @@ -255,7 +321,25 @@ auto sourcemeta::jsonschema::lint(const sourcemeta::core::Options &options) result = false; } - if (copy != entry.second) { + if (format_output) { + if (!keep_ordering) { + sourcemeta::core::format(copy, sourcemeta::core::schema_walker, + custom_resolver, dialect); + } + + std::ostringstream expected; + sourcemeta::core::prettify(copy, expected, indentation); + expected << "\n"; + + std::ifstream current_stream{entry.first}; + std::ostringstream current; + current << current_stream.rdbuf(); + + if (current.str() != expected.str()) { + std::ofstream output{entry.first}; + output << expected.str(); + } + } else if (copy != entry.second) { std::ofstream output{entry.first}; sourcemeta::core::prettify(copy, output, indentation); output << "\n"; @@ -275,14 +359,16 @@ auto sourcemeta::jsonschema::lint(const sourcemeta::core::Options &options) resolver(options, options.contains("http"), dialect, configuration)}; LOG_VERBOSE(options) << "Linting: " << entry.first.string() << "\n"; + bool printed_progress{false}; const auto wrapper_result = sourcemeta::jsonschema::try_catch(options, [&]() { try { const auto subresult = bundle.check( entry.second, sourcemeta::core::schema_walker, custom_resolver, - get_lint_callback(errors_array, entry, output_json), dialect, - sourcemeta::jsonschema::default_id(entry.first), + get_lint_callback(errors_array, entry, output_json, false, + printed_progress), + dialect, sourcemeta::jsonschema::default_id(entry.first), EXCLUDE_KEYWORD); scores.emplace_back(subresult.second); if (subresult.first) { diff --git a/vendor/jsonschema/src/command_metaschema.cc b/vendor/jsonschema/src/command_metaschema.cc index b7aaa164..c7bb78f4 100644 --- a/vendor/jsonschema/src/command_metaschema.cc +++ b/vendor/jsonschema/src/command_metaschema.cc @@ -65,8 +65,8 @@ auto sourcemeta::jsonschema::metaschema( if (!cache.contains(std::string{dialect})) { const auto metaschema_template{sourcemeta::blaze::compile( bundled, sourcemeta::core::schema_walker, custom_resolver, - sourcemeta::blaze::default_schema_compiler, frame, - sourcemeta::blaze::Mode::Exhaustive, default_dialect_option)}; + sourcemeta::blaze::default_schema_compiler, frame, frame.root(), + sourcemeta::blaze::Mode::Exhaustive)}; cache.insert({std::string{dialect}, metaschema_template}); } diff --git a/vendor/jsonschema/src/command_validate.cc b/vendor/jsonschema/src/command_validate.cc index 8ee5e127..580eeba0 100644 --- a/vendor/jsonschema/src/command_validate.cc +++ b/vendor/jsonschema/src/command_validate.cc @@ -37,8 +37,7 @@ auto get_precompiled_schema_template_path( auto get_schema_template(const sourcemeta::core::JSON &bundled, const sourcemeta::core::SchemaResolver &resolver, const sourcemeta::core::SchemaFrame &frame, - const std::string_view default_dialect, - const std::string_view default_id, + const std::string &entrypoint_uri, const bool fast_mode, const sourcemeta::core::Options &options) -> sourcemeta::blaze::Template { @@ -63,10 +62,9 @@ auto get_schema_template(const sourcemeta::core::JSON &bundled, return sourcemeta::blaze::compile( bundled, sourcemeta::core::schema_walker, resolver, - sourcemeta::blaze::default_schema_compiler, frame, + sourcemeta::blaze::default_schema_compiler, frame, entrypoint_uri, fast_mode ? sourcemeta::blaze::Mode::FastValidation - : sourcemeta::blaze::Mode::Exhaustive, - default_dialect, default_id); + : sourcemeta::blaze::Mode::Exhaustive); } auto parse_loop(const sourcemeta::core::Options &options) -> std::uint64_t { @@ -173,6 +171,12 @@ auto sourcemeta::jsonschema::validate(const sourcemeta::core::Options &options) const auto trace{options.contains("trace")}; const auto json_output{options.contains("json")}; + if (options.contains("entrypoint") && !options.at("entrypoint").empty() && + options.contains("template") && !options.at("template").empty()) { + throw OptionConflictError{ + "The --entrypoint option cannot be used with --template"}; + } + const auto schema_default_id{sourcemeta::jsonschema::default_id(schema_path)}; const sourcemeta::core::JSON bundled{[&]() { @@ -232,10 +236,24 @@ auto sourcemeta::jsonschema::validate(const sourcemeta::core::Options &options) throw FileError(schema_path, error.what()); } + std::string entrypoint_uri{frame.root()}; + if (options.contains("entrypoint") && !options.at("entrypoint").empty()) { + try { + entrypoint_uri = resolve_entrypoint( + frame, std::string{options.at("entrypoint").front()}); + } catch (const sourcemeta::blaze::CompilerInvalidEntryPoint &error) { + throw FileError(schema_path, + error); + } + } + const auto schema_template{[&]() { try { - return get_schema_template(bundled, custom_resolver, frame, dialect, - schema_default_id, fast_mode, options); + return get_schema_template(bundled, custom_resolver, frame, + entrypoint_uri, fast_mode, options); + } catch (const sourcemeta::blaze::CompilerInvalidEntryPoint &error) { + throw FileError(schema_path, + error); } catch ( const sourcemeta::blaze::CompilerReferenceTargetNotSchemaError &error) { throw FileError( diff --git a/vendor/jsonschema/src/error.h b/vendor/jsonschema/src/error.h index e1c8d685..c4fb3561 100644 --- a/vendor/jsonschema/src/error.h +++ b/vendor/jsonschema/src/error.h @@ -448,6 +448,16 @@ inline auto try_catch(const sourcemeta::core::Options &options, } } + return EXIT_FAILURE; + } catch ( + const FileError &error) { + const auto is_json{options.contains("json")}; + print_exception(is_json, error); + if (!is_json) { + std::cerr + << "\nUse the `inspect` command to find valid schema locations\n"; + } + return EXIT_FAILURE; } catch (const FileError &error) { const auto is_json{options.contains("json")}; diff --git a/vendor/jsonschema/src/main.cc b/vendor/jsonschema/src/main.cc index 356be1c3..3facc655 100644 --- a/vendor/jsonschema/src/main.cc +++ b/vendor/jsonschema/src/main.cc @@ -37,7 +37,7 @@ Global Options: validate [--benchmark/-b] [--loop ] [--extension/-e ] [--ignore/-i ] [--trace/-t] [--fast/-f] - [--template/-m ] + [--template/-m ] [--entrypoint/-p ] Validate one or more instances against the given schema. @@ -60,10 +60,11 @@ Global Options: compile [--extension/-e ] [--ignore/-i ] [--fast/-f] [--minify/-m] - [--include/-n ] + [--include/-n ] [--entrypoint/-p ] Compile the given schema into an internal optimised representation. Use --include/-n to output as a C/C++ header file. + Use --entrypoint/-p to compile a subschema by JSON Pointer or URI. test [schemas-or-directories...] [--extension/-e ] [--ignore/-i ] @@ -78,14 +79,17 @@ Global Options: Format the input schemas in-place or check they are formatted. This command does not support YAML schemas yet. - lint [schemas-or-directories...] [--fix/-f] [--extension/-e ] + lint [schemas-or-directories...] [--fix/-f] [--format/-m] + [--keep-ordering/-k] [--extension/-e ] [--ignore/-i ] [--exclude/-x ] [--only/-o ] [--list/-l] [--indentation/-n ] Lint the input schemas and potentially fix the reported issues. The --fix/-f option is not supported when passing YAML schemas. + Use --format/-m with --fix to format the output even when there + are no linting issues. + Use --keep-ordering/-k with --format to preserve key order. Use --list/-l to print a summary of all enabled rules. - Use --indentation/-n to keep indentation when auto-fixing bundle [--extension/-e ] [--ignore/-i ] [--without-id/-w] @@ -146,6 +150,8 @@ auto jsonschema_main(const std::string &program, const std::string &command, return EXIT_SUCCESS; } else if (command == "lint") { app.flag("fix", {"f"}); + app.flag("format", {"m"}); + app.flag("keep-ordering", {"k"}); app.flag("list", {"l"}); app.option("extension", {"e"}); app.option("exclude", {"x"}); @@ -163,6 +169,7 @@ auto jsonschema_main(const std::string &program, const std::string &command, app.option("ignore", {"i"}); app.option("template", {"m"}); app.option("loop", {"l"}); + app.option("entrypoint", {"p"}); app.parse(argc, argv, {.skip = 1}); sourcemeta::jsonschema::validate(app); return EXIT_SUCCESS; @@ -177,6 +184,7 @@ auto jsonschema_main(const std::string &program, const std::string &command, app.flag("fast", {"f"}); app.flag("minify", {"m"}); app.option("include", {"n"}); + app.option("entrypoint", {"p"}); app.parse(argc, argv, {.skip = 1}); sourcemeta::jsonschema::compile(app); return EXIT_SUCCESS; diff --git a/vendor/jsonschema/src/utils.h b/vendor/jsonschema/src/utils.h index 2973bba0..eec8c652 100644 --- a/vendor/jsonschema/src/utils.h +++ b/vendor/jsonschema/src/utils.h @@ -4,10 +4,12 @@ #include #include #include +#include #include #include #include +#include #include #include // assert @@ -29,6 +31,35 @@ inline auto default_id(const std::filesystem::path &schema_path) .recompose(); } +inline auto resolve_entrypoint(const sourcemeta::core::SchemaFrame &frame, + const std::string &entrypoint) -> std::string { + if (entrypoint.empty()) { + return std::string{frame.root()}; + } + + if (entrypoint.front() == '/' && + (entrypoint.size() < 2 || entrypoint[1] != '/')) { + sourcemeta::core::URI result{std::string{frame.root()}}; + result.fragment(entrypoint); + return result.recompose(); + } + + if (entrypoint.front() == '#') { + const std::string pointer_string{entrypoint.substr(1)}; + sourcemeta::core::URI result{std::string{frame.root()}}; + result.fragment(pointer_string); + return result.recompose(); + } + + try { + const sourcemeta::core::URI uri{entrypoint}; + return entrypoint; + } catch (const sourcemeta::core::URIParseError &) { + throw sourcemeta::blaze::CompilerInvalidEntryPoint{ + entrypoint, "The given entry point is not a valid URI or JSON Pointer"}; + } +} + inline auto default_dialect( const sourcemeta::core::Options &options, const std::optional &configuration)