Skip to content

Commit

Permalink
Add basic custom resolution features
Browse files Browse the repository at this point in the history
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
  • Loading branch information
jviotti committed May 27, 2024
1 parent a9b0f4d commit 3aeee6d
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 13 deletions.
1 change: 1 addition & 0 deletions README.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ without passing a command will print convenient reference documentation:
The following global options apply to all commands:

- `--verbose / -v`: Enable verbose output
- `--resolve / -r`: Import the given JSON Schema into the resolution context

Coming Soon
-----------
Expand Down
6 changes: 2 additions & 4 deletions docs/bundle.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@ The JSON Schema CLI supports this functionality through the `bundle` command.
Examples
--------

<!-- TODO: Actually exemplify real remote bundling -->

### Bundle a JSON Schema
### Bundle a JSON Schema preloading another one

```sh
jsonschema bundle path/to/my/schema.json
jsonschema bundle path/to/my/schema.json --resolve path/to/external.json
```
2 changes: 1 addition & 1 deletion src/command_bundle.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
auto intelligence::jsonschema::cli::bundle(
const std::span<const std::string> &arguments) -> int {
const auto options{parse_options(arguments, {})};
CLI_ENSURE(!options.at("").empty(), "You must pass a JSON Schema as input")
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))
Expand Down
1 change: 1 addition & 0 deletions src/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ 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
Commands:
Expand Down
50 changes: 42 additions & 8 deletions src/utils.cc
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#include "utils.h"

#include <cassert> // assert
#include <fstream> // std::ofstream
#include <iostream> // std::cerr
#include <optional> // std::optional, std::nullopt
#include <sstream> // std::ostringstream
#include <cassert> // assert
#include <fstream> // std::ofstream
#include <iostream> // std::cerr
#include <optional> // std::optional, std::nullopt
#include <sstream> // std::ostringstream
#include <stdexcept> // std::runtime_error

namespace {

Expand Down Expand Up @@ -116,10 +117,43 @@ auto pretty_evaluate_callback(
std::cerr << "\")\n";
}

// TODO: Use input options to get a custom-made resolver
auto resolver(const std::map<std::string, std::vector<std::string>> &)
auto resolver(const std::map<std::string, std::vector<std::string>> &options)
-> sourcemeta::jsontoolkit::SchemaResolver {
return sourcemeta::jsontoolkit::official_resolver;
if (!options.contains("resolve") && !options.contains("r")) {
return sourcemeta::jsontoolkit::official_resolver;
}

std::map<std::string, sourcemeta::jsontoolkit::JSON> schemas;
const std::string option{options.contains("resolve") ? "resolve" : "r"};
for (const auto &schema_path : options.at(option)) {
const auto schema{sourcemeta::jsontoolkit::from_file(schema_path)};
// TODO: Use the current resolver as its building up
const auto id{sourcemeta::jsontoolkit::id(
schema, sourcemeta::jsontoolkit::official_resolver)
.get()};
if (!id.has_value()) {
std::ostringstream error;
error << "Cannot determine the identifier of the schema: " << schema_path;
throw std::runtime_error(error.str());
}

// TODO: Throw if we are overriding with a duplicate id
// TODO: We need to frame to add subschemas too?
schemas.insert({id.value(), schema});
log_verbose(options) << "Loading schema: " << schema_path << "\n";
}

return [schemas](std::string_view identifier)
-> std::future<std::optional<sourcemeta::jsontoolkit::JSON>> {
const std::string string_identifier{identifier};
if (schemas.contains(string_identifier)) {
std::promise<std::optional<sourcemeta::jsontoolkit::JSON>> promise;
promise.set_value(schemas.at(string_identifier));
return promise.get_future();
}

return sourcemeta::jsontoolkit::official_resolver(identifier);
};
}

auto log_verbose(const std::map<std::string, std::vector<std::string>> &options)
Expand Down
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ add_jsonschema_test_unix(frame)
add_jsonschema_test_unix(validate_pass)
add_jsonschema_test_unix(validate_fail)
add_jsonschema_test_unix(bundle_non_remote)
add_jsonschema_test_unix(bundle_remote_single_schema)
add_jsonschema_test_unix(test_single_pass)
add_jsonschema_test_unix(test_single_fail)
43 changes: 43 additions & 0 deletions test/bundle_remote_single_schema.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/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

cat << 'EOF' > "$TMP/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/remote.json" > "$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"

0 comments on commit 3aeee6d

Please sign in to comment.