Skip to content

Commit c14a91b

Browse files
committed
feat(validate): remove flags from parse-options
1 parent ce04060 commit c14a91b

File tree

1 file changed

+50
-29
lines changed

1 file changed

+50
-29
lines changed

src/command_validate.cc

Lines changed: 50 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
#include <sourcemeta/core/json.h>
22
#include <sourcemeta/core/jsonl.h>
3-
#include <sourcemeta/core/jsonschema.h>
43
#include <sourcemeta/core/jsonpointer.h>
4+
#include <sourcemeta/core/jsonschema.h>
55

66
#include <sourcemeta/blaze/compiler.h>
77
#include <sourcemeta/blaze/evaluator.h>
88

9-
#include <chrono> // std::chrono
10-
#include <cstdlib> // EXIT_SUCCESS, EXIT_FAILURE
9+
#include <chrono> // std::chrono
10+
#include <cstdlib> // EXIT_SUCCESS, EXIT_FAILURE
1111
#include <filesystem>
1212
#include <iostream> // std::cerr
1313
#include <optional> // std::optional
@@ -25,48 +25,64 @@
2525
auto sourcemeta::jsonschema::cli::validate(
2626
const std::span<const std::string> &arguments) -> int {
2727
const auto options{
28-
parse_options(arguments, {"h", "http", "b", "benchmark", "t", "trace",
29-
"p", "path"})};
28+
parse_options(arguments, {"h", "http", "b", "benchmark", "t", "trace"})};
29+
30+
auto leftover = options.at("");
3031

31-
if (options.at("").size() < 1) {
32+
// Attempt to extract a pointer value from leftover arguments:
33+
// --path=<pointer>
34+
// --path <pointer>
35+
// -p <pointer>
36+
std::optional<std::string> pointer_option;
37+
for (auto it = leftover.begin(); it != leftover.end();) {
38+
const auto &arg = *it;
39+
40+
// a) --path=/something
41+
if (arg.rfind("--path=", 0) == 0) {
42+
pointer_option = arg.substr(7);
43+
it = leftover.erase(it);
44+
}
45+
// b) --path or -p, next token is the pointer
46+
else if (arg == "--path" || arg == "-p") {
47+
it = leftover.erase(it);
48+
if (it != leftover.end()) {
49+
pointer_option = *it;
50+
it = leftover.erase(it);
51+
} else {
52+
std::cerr << "error: The '--path' option requires a pointer.\n";
53+
return EXIT_FAILURE;
54+
}
55+
} else {
56+
++it;
57+
}
58+
}
59+
60+
if (leftover.size() < 1) {
3261
std::cerr
3362
<< "error: This command expects a path to a schema and a path to an\n"
3463
<< "instance to validate against the schema. For example:\n\n"
3564
<< " jsonschema validate path/to/schema.json path/to/instance.json\n";
3665
return EXIT_FAILURE;
3766
}
38-
39-
if (options.at("").size() < 2) {
67+
if (leftover.size() < 2) {
4068
std::cerr
4169
<< "error: In addition to the schema, you must also pass an argument\n"
4270
<< "that represents the instance to validate against. For example:\n\n"
4371
<< " jsonschema validate path/to/schema.json path/to/instance.json\n";
4472
return EXIT_FAILURE;
4573
}
4674

47-
const auto &schema_path{options.at("").at(0)};
75+
const auto &schema_path = leftover[0];
4876
const auto custom_resolver{
4977
resolver(options, options.contains("h") || options.contains("http"))};
5078

5179
const auto schema{sourcemeta::jsonschema::cli::read_file(schema_path)};
5280

53-
// Extract optional JSON Pointer from --path/-p
54-
std::optional<std::string> pointer_option;
55-
if (options.contains("p") && !options.at("p").empty()) {
56-
pointer_option = options.at("p").at(0);
57-
} else if (options.contains("path") && !options.at("path").empty()) {
58-
pointer_option = options.at("path").at(0);
59-
}
60-
61-
// Start by copying the entire schema, then override if pointer is given
6281
sourcemeta::core::JSON resolved_schema{schema};
63-
6482
if (pointer_option.has_value()) {
65-
// Convert pointer string -> sourcemeta::core::Pointer
6683
const auto pointer = sourcemeta::core::to_pointer(pointer_option.value());
67-
// Attempt to get the sub-schema
6884
const auto *maybe_ptr = sourcemeta::core::try_get(schema, pointer);
69-
if (maybe_ptr == nullptr) {
85+
if (!maybe_ptr) {
7086
std::cerr << "error: Failed to resolve JSON Pointer '"
7187
<< pointer_option.value() << "' in the provided schema\n "
7288
<< std::filesystem::canonical(schema_path).string() << "\n";
@@ -78,9 +94,16 @@ auto sourcemeta::jsonschema::cli::validate(
7894

7995
// Validate that the final resolved_schema is indeed a valid JSON Schema
8096
if (!sourcemeta::core::is_schema(resolved_schema)) {
81-
std::cerr << "error: The schema (or sub-schema) you provided does not\n"
82-
<< "represent a valid JSON Schema\n "
83-
<< std::filesystem::canonical(schema_path).string() << "\n";
97+
if (!pointer_option.has_value()) {
98+
std::cerr << "error: The schema file you provided does not represent a "
99+
"valid JSON Schema\n "
100+
<< std::filesystem::canonical(schema_path).string() << "\n";
101+
} else {
102+
std::cerr << "error: The sub-schema at pointer '"
103+
<< pointer_option.value()
104+
<< "' does not represent a valid JSON Schema\n "
105+
<< std::filesystem::canonical(schema_path).string() << "\n";
106+
}
84107
return EXIT_FAILURE;
85108
}
86109

@@ -93,10 +116,8 @@ auto sourcemeta::jsonschema::cli::validate(
93116

94117
bool result{true};
95118

96-
auto iterator{options.at("").cbegin()};
97-
std::advance(iterator, 1);
98-
for (; iterator != options.at("").cend(); ++iterator) {
99-
const std::filesystem::path instance_path{*iterator};
119+
for (std::size_t i = 1; i < leftover.size(); ++i) {
120+
const std::filesystem::path instance_path{leftover[i]};
100121
if (instance_path.extension() == ".jsonl") {
101122
log_verbose(options)
102123
<< "Interpreting input as JSONL: "

0 commit comments

Comments
 (0)