From 10d3117d2a614ea1ec85ad9091a8d7e460bf76ec Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Tue, 4 Jun 2024 11:07:55 -0400 Subject: [PATCH] Extend the `--resolve` option to take directories of schemas (#55) Signed-off-by: Juan Cruz Viotti --- docs/bundle.markdown | 9 ++++++- docs/test.markdown | 10 ++++++-- docs/validate.markdown | 13 ++++++++-- src/main.cc | 3 ++- src/utils.cc | 14 ++++++----- test/CMakeLists.txt | 1 + test/bundle_remote_directory.sh | 44 +++++++++++++++++++++++++++++++++ 7 files changed, 82 insertions(+), 12 deletions(-) create mode 100755 test/bundle_remote_directory.sh diff --git a/docs/bundle.markdown b/docs/bundle.markdown index 2f10b433..13a986eb 100644 --- a/docs/bundle.markdown +++ b/docs/bundle.markdown @@ -3,7 +3,7 @@ Bundling ```sh jsonschema bundle - [--http/-h] [--verbose/-v] [--resolve/-r ...] + [--http/-h] [--verbose/-v] [--resolve/-r ...] ``` A schema may contain references to remote schemas outside the scope of the @@ -77,6 +77,13 @@ jsonschema bundle path/to/my/schema.json \ --resolve path/to/three.json ``` +### Bundle a JSON Schema importing a directory of `.schema.json` schemas + +```sh +jsonschema bundle path/to/my/schema.json \ + --resolve path/to/schemas --extension schema.json +``` + ### Bundle a JSON Schema while enabling HTTP resolution ```sh diff --git a/docs/test.markdown b/docs/test.markdown index 28ce5345..6a4f082e 100644 --- a/docs/test.markdown +++ b/docs/test.markdown @@ -7,8 +7,8 @@ Testing ```sh jsonschema test [schemas-or-directories...] - [--http/-h] [--metaschema/-m] [--verbose/-v] [--resolve/-r ...] - [--extension/-e ] + [--http/-h] [--metaschema/-m] [--verbose/-v] + [--resolve/-r ...] [--extension/-e ] ``` Schemas are code. As such, you should run an automated unit testing suite @@ -91,3 +91,9 @@ jsonschema test path/to/test.json --http ```sh jsonschema test path/to/test.json --resolve path/to/external.json ``` + +### Run a single test definition importing a directory of `.schema.json` schemas + +```sh +jsonschema test path/to/test.json --resolve path/to/schemas --extension schema.json +``` diff --git a/docs/validate.markdown b/docs/validate.markdown index 53dc8370..49c4d10d 100644 --- a/docs/validate.markdown +++ b/docs/validate.markdown @@ -7,7 +7,8 @@ Validating ```sh jsonschema validate - [instance.json] [--http/-h] [--metaschema/-m] [--verbose/-v] [--resolve/-r ...] + [instance.json] [--http/-h] [--metaschema/-m] [--verbose/-v] + [--resolve/-r ...] ``` The most popular use case of JSON Schema is to validate JSON documents. The @@ -72,5 +73,13 @@ jsonschema validate path/to/my/schema.json path/to/my/instance.json --http ### Validate a JSON instance importing a single local schema ```sh -jsonschema validate path/to/my/schema.json path/to/my/instance.json --resolve path/to/external.json +jsonschema validate path/to/my/schema.json path/to/my/instance.json \ + --resolve path/to/external.json +``` + +### Validate a JSON instance importing a directory of `.schema.jsin` schemas + +```sh +jsonschema validate path/to/my/schema.json path/to/my/instance.json \ + --resolve path/to/schemas --extension schema.json ``` diff --git a/src/main.cc b/src/main.cc index 5b2c8fde..6ea16e2d 100644 --- a/src/main.cc +++ b/src/main.cc @@ -16,7 +16,8 @@ constexpr std::string_view USAGE_DETAILS{R"EOF( Global Options: --verbose, -v Enable verbose output - --resolve, -r Import the given JSON Schema into the resolution context + --resolve, -r Import the given JSON Schema (or directory of schemas) + into the resolution context Commands: diff --git a/src/utils.cc b/src/utils.cc index 4c6ca411..24ae4bed 100644 --- a/src/utils.cc +++ b/src/utils.cc @@ -202,16 +202,18 @@ auto resolver(const std::map> &options, }}; if (options.contains("resolve")) { - for (const auto &schema_path : options.at("resolve")) { - log_verbose(options) << "Loading schema: " << schema_path << "\n"; - dynamic_resolver.add(sourcemeta::jsontoolkit::from_file(schema_path)); + for (const auto &entry : + for_each_json(options.at("resolve"), parse_extensions(options))) { + log_verbose(options) << "Loading schema: " << entry.first << "\n"; + dynamic_resolver.add(entry.second); } } if (options.contains("r")) { - for (const auto &schema_path : options.at("r")) { - log_verbose(options) << "Loading schema: " << schema_path << "\n"; - dynamic_resolver.add(sourcemeta::jsontoolkit::from_file(schema_path)); + for (const auto &entry : + for_each_json(options.at("r"), parse_extensions(options))) { + log_verbose(options) << "Loading schema: " << entry.first << "\n"; + dynamic_resolver.add(entry.second); } } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2b53398e..641e6211 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -33,6 +33,7 @@ add_jsonschema_test_unix(validate_fail_only_metaschema) add_jsonschema_test_unix(bundle_non_remote) add_jsonschema_test_unix(bundle_remote_single_schema) add_jsonschema_test_unix(bundle_remote_no_http) +add_jsonschema_test_unix(bundle_remote_directory) add_jsonschema_test_unix(test_single_pass) add_jsonschema_test_unix(test_single_fail) add_jsonschema_test_unix(test_single_unsupported) diff --git a/test/bundle_remote_directory.sh b/test/bundle_remote_directory.sh new file mode 100755 index 00000000..c5b054ae --- /dev/null +++ b/test/bundle_remote_directory.sh @@ -0,0 +1,44 @@ +#!/bin/sh + +set -o errexit +set -o nounset + +TMP="$(mktemp -d)" +clean() { rm -rf "$TMP"; } +trap clean EXIT + +cat << 'EOF' > "$TMP/schema.json" +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://example.com", + "$ref": "nested" +} +EOF + +mkdir "$TMP/schemas" +cat << 'EOF' > "$TMP/schemas/remote.json" +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://example.com/nested", + "type": "string" +} +EOF + +"$1" bundle "$TMP/schema.json" --resolve "$TMP/schemas" > "$TMP/result.json" + +cat << 'EOF' > "$TMP/expected.json" +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://example.com", + "$ref": "nested", + "$defs": { + "https://example.com/nested": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://example.com/nested", + "type": "string" + } + } +} +EOF + +diff "$TMP/result.json" "$TMP/expected.json"