diff --git a/DEPENDENCIES b/DEPENDENCIES index e3ec42e5..c8c5a78d 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -1,4 +1,4 @@ vendorpull https://github.com/sourcemeta/vendorpull dea311b5bfb53b6926a4140267959ae334d3ecf4 noa https://github.com/sourcemeta/noa 2bc3138b80e575786bec418c91fc2058c6836993 -jsontoolkit https://github.com/sourcemeta/jsontoolkit e8eddd077e4d7af996fd892a19ef8ad244ff3d59 +jsontoolkit https://github.com/sourcemeta/jsontoolkit 0e2ac8987382685ad6dc50ca33d2e43a6701b023 hydra https://github.com/sourcemeta/hydra 3c53d3fdef79e9ba603d48470a508cc45472a0dc diff --git a/docs/bundle.markdown b/docs/bundle.markdown index 3bdd5ddd..91d17afe 100644 --- a/docs/bundle.markdown +++ b/docs/bundle.markdown @@ -4,7 +4,8 @@ Bundling ```sh jsonschema bundle [--http/-h] [--verbose/-v] [--resolve/-r ...] - [--ignore/-i ] + [--extension/-e ] [--ignore/-i ] + [--without-id/-w] ``` A schema may contain references to remote schemas outside the scope of the @@ -16,6 +17,18 @@ to resolve remote references in advance and inline them into the given schema for local consumption or further distribution. The JSON Schema CLI supports this functionality through the `bundle` command. +> [!WARNING] +> A popular use case for JSON Schema is providing auto-completion for code +> editors. If you plan to use your bundled schema for this, keep in mind that +> at the time of this writing, Visual Studio Code ships with a +> [non-compliant](https://bowtie.report/#/implementations/ts-vscode-json-languageservice) +> implementation that [does not support the `$id` and `id` +> keywords](https://github.com/microsoft/vscode-json-languageservice/issues/224) +> and that will fail to handle most bundled schemas. As a workaround, we offer +> the `--without-id`/`-w` option to perform bundling without relying on +> identifiers to make your resulting schemas compatible with Visual Studio +> Code. + Examples -------- @@ -97,3 +110,9 @@ jsonschema bundle path/to/my/schema.json \ ```sh jsonschema bundle path/to/my/schema.json --http ``` + +### Bundle a JSON Schema without identifiers and importing a single local schema + +```sh +jsonschema bundle path/to/my/schema.json --resolve path/to/external.json --without-id +``` diff --git a/src/command_bundle.cc b/src/command_bundle.cc index 581065ce..a93d890e 100644 --- a/src/command_bundle.cc +++ b/src/command_bundle.cc @@ -9,13 +9,26 @@ auto intelligence::jsonschema::cli::bundle( const std::span &arguments) -> int { - const auto options{parse_options(arguments, {"h", "http"})}; + const auto options{ + parse_options(arguments, {"h", "http", "w", "without-id"})}; CLI_ENSURE(!options.at("").empty(), "You must pass a JSON Schema as input"); auto schema{sourcemeta::jsontoolkit::from_file(options.at("").front())}; - sourcemeta::jsontoolkit::bundle( - schema, sourcemeta::jsontoolkit::default_schema_walker, - resolver(options, options.contains("h") || options.contains("http"))) - .wait(); + + if (options.contains("w") || options.contains("without-id")) { + log_verbose(options) << "Bundling without using identifiers\n"; + sourcemeta::jsontoolkit::bundle( + schema, sourcemeta::jsontoolkit::default_schema_walker, + resolver(options, options.contains("h") || options.contains("http")), + sourcemeta::jsontoolkit::BundleOptions::WithoutIdentifiers) + .wait(); + } else { + sourcemeta::jsontoolkit::bundle( + schema, sourcemeta::jsontoolkit::default_schema_walker, + resolver(options, options.contains("h") || options.contains("http")), + sourcemeta::jsontoolkit::BundleOptions::Default) + .wait(); + } + sourcemeta::jsontoolkit::prettify( schema, std::cout, sourcemeta::jsontoolkit::schema_format_compare); std::cout << std::endl; diff --git a/src/main.cc b/src/main.cc index f264401e..7d57908e 100644 --- a/src/main.cc +++ b/src/main.cc @@ -43,11 +43,12 @@ Global Options: Format the input schemas in-place or check they are formatted. lint [schemas-or-directories...] [--fix/-f] [--extension/-e ] - [--ignore/-i ] + [--ignore/-i ] Lint the input schemas and potentially fix the reported issues. - bundle [--http/-h] + bundle [--http/-h] [--extension/-e ] + [--ignore/-i ] [--without-id/-w] Perform JSON Schema Bundling on a schema to inline remote references, printing the result to standard output. diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6916913a..cc3d1ec1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -39,6 +39,7 @@ 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(bundle_remote_directory_without_id) 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_without_id.sh b/test/bundle_remote_directory_without_id.sh new file mode 100755 index 00000000..c7c856b2 --- /dev/null +++ b/test/bundle_remote_directory_without_id.sh @@ -0,0 +1,42 @@ +#!/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" --without-id > "$TMP/result.json" + +cat << 'EOF' > "$TMP/expected.json" +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$ref": "#/$defs/https%3A~1~1example.com~1nested", + "$defs": { + "https://example.com/nested": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "string" + } + } +} +EOF + +diff "$TMP/result.json" "$TMP/expected.json" diff --git a/vendor/jsontoolkit/src/jsonschema/bundle.cc b/vendor/jsontoolkit/src/jsonschema/bundle.cc index 84a13762..2827b90c 100644 --- a/vendor/jsontoolkit/src/jsonschema/bundle.cc +++ b/vendor/jsontoolkit/src/jsonschema/bundle.cc @@ -160,6 +160,10 @@ auto remove_identifiers(sourcemeta::jsontoolkit::JSON &schema, for (const auto &entry : sourcemeta::jsontoolkit::SchemaIterator{ schema, walker, resolver, default_dialect}) { auto &subschema{sourcemeta::jsontoolkit::get(schema, entry.pointer)}; + if (subschema.is_boolean()) { + continue; + } + subschema.erase(id_keyword(entry.vocabularies)); if (entry.vocabularies.contains(