Skip to content

Commit 9cc007f

Browse files
committed
[WIP] Start refactoring and simplifying CLI boilerplate code
Signed-off-by: Juan Cruz Viotti <[email protected]>
1 parent 9759a4c commit 9cc007f

13 files changed

+134
-169
lines changed

src/command_bundle.cc

+16-23
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#include <sourcemeta/core/json.h>
22
#include <sourcemeta/core/jsonschema.h>
33

4-
#include <cstdlib> // EXIT_SUCCESS
4+
#include <cstdlib> // EXIT_SUCCESS, EXIT_FAILURE
55
#include <iostream> // std::cout
66

77
#include "command.h"
@@ -11,37 +11,30 @@ auto sourcemeta::jsonschema::cli::bundle(
1111
const std::span<const std::string> &arguments) -> int {
1212
const auto options{
1313
parse_options(arguments, {"h", "http", "w", "without-id"})};
14-
const auto dialect{default_dialect(options)};
15-
1614
if (options.at("").size() < 1) {
17-
std::cerr
18-
<< "error: This command expects a path to a schema. For example:\n\n"
19-
<< " jsonschema bundle path/to/schema.json\n";
15+
log_error() << "This command expects a path to a schema. For example:\n\n"
16+
<< " jsonschema bundle path/to/schema.json\n";
2017
return EXIT_FAILURE;
2118
}
2219

23-
const auto custom_resolver{resolver(
24-
options, options.contains("h") || options.contains("http"), dialect)};
25-
auto schema{sourcemeta::jsonschema::cli::read_file(options.at("").front())};
26-
20+
const auto default_dialect{infer_default_dialect(options)};
21+
const auto resolver{infer_resolver(options, default_dialect)};
22+
auto schema{read_yaml_or_json(options.at("").front())};
2723
sourcemeta::core::bundle(schema, sourcemeta::core::schema_official_walker,
28-
custom_resolver, dialect);
24+
resolver, default_dialect);
2925

3026
if (options.contains("w") || options.contains("without-id")) {
31-
std::cerr << "warning: You are opting in to remove schema identifiers in "
32-
"the bundled schema.\n";
33-
std::cerr << "The only legit use case of this advanced feature we know of "
34-
"it to workaround\n";
35-
std::cerr << "non-compliant JSON Schema implementations such as Visual "
36-
"Studio Code.\n";
37-
std::cerr << "In other case, this is not needed and may harm other use "
38-
"cases. For example,\n";
39-
std::cerr << "you will be unable to reference the resulting schema from "
40-
"other schemas\n";
41-
std::cerr << "using the --resolve/-r option.\n";
27+
log_warning()
28+
<< "You are opting in to remove schema identifiers in "
29+
"the bundled schema.\nThe only legit use case of this "
30+
"advanced feature we know of it to workaround\nnon-compliant "
31+
"JSON Schema implementations such as Visual Studio Code.\nIn "
32+
"other case, this is not needed and may harm other use cases. "
33+
"For example,\nyou will be unable to reference the resulting "
34+
"schema from other schemas\nusing the --resolve/-r option.\n";
4235
sourcemeta::core::unidentify(schema,
4336
sourcemeta::core::schema_official_walker,
44-
custom_resolver, dialect);
37+
resolver, default_dialect);
4538
}
4639

4740
sourcemeta::core::prettify(schema, std::cout,

src/command_decode.cc

+5-6
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ static auto has_data(std::ifstream &stream) -> bool {
2727

2828
auto sourcemeta::jsonschema::cli::decode(
2929
const std::span<const std::string> &arguments) -> int {
30-
const auto options{parse_options(arguments, {})};
30+
const auto options{parse_options(arguments, {"h", "http"})};
3131

3232
if (options.at("").size() < 2) {
3333
std::cerr
@@ -42,11 +42,10 @@ auto sourcemeta::jsonschema::cli::decode(
4242
"$schema": "https://json-schema.org/draft/2020-12/schema"
4343
})JSON")};
4444

45-
const auto dialect{default_dialect(options)};
46-
sourcemeta::jsonbinpack::compile(
47-
schema, sourcemeta::core::schema_official_walker,
48-
resolver(options, options.contains("h") || options.contains("http"),
49-
dialect));
45+
const auto default_dialect{infer_default_dialect(options)};
46+
sourcemeta::jsonbinpack::compile(schema,
47+
sourcemeta::core::schema_official_walker,
48+
infer_resolver(options, default_dialect));
5049
const auto encoding{sourcemeta::jsonbinpack::load(schema)};
5150

5251
std::ifstream input_stream{sourcemeta::jsonschema::cli::safe_weakly_canonical(

src/command_encode.cc

+6-8
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
auto sourcemeta::jsonschema::cli::encode(
1616
const std::span<const std::string> &arguments) -> int {
17-
const auto options{parse_options(arguments, {})};
17+
const auto options{parse_options(arguments, {"h", "http"})};
1818

1919
if (options.at("").size() < 2) {
2020
std::cerr
@@ -29,11 +29,10 @@ auto sourcemeta::jsonschema::cli::encode(
2929
"$schema": "https://json-schema.org/draft/2020-12/schema"
3030
})JSON")};
3131

32-
const auto dialect{default_dialect(options)};
33-
sourcemeta::jsonbinpack::compile(
34-
schema, sourcemeta::core::schema_official_walker,
35-
resolver(options, options.contains("h") || options.contains("http"),
36-
dialect));
32+
const auto default_dialect{infer_default_dialect(options)};
33+
sourcemeta::jsonbinpack::compile(schema,
34+
sourcemeta::core::schema_official_walker,
35+
infer_resolver(options, default_dialect));
3736
const auto encoding{sourcemeta::jsonbinpack::load(schema)};
3837

3938
const std::filesystem::path document{options.at("").front()};
@@ -64,8 +63,7 @@ auto sourcemeta::jsonschema::cli::encode(
6463
<< (static_cast<std::uint64_t>(total_size) * 100 / original_size)
6564
<< "%\n";
6665
} else {
67-
const auto entry{
68-
sourcemeta::jsonschema::cli::read_file(options.at("").front())};
66+
const auto entry{read_yaml_or_json(options.at("").front())};
6967
std::ofstream output_stream(safe_weakly_canonical(options.at("").at(1)),
7068
std::ios::binary);
7169
output_stream.exceptions(std::ios_base::badbit);

src/command_fmt.cc

+3-5
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,9 @@ auto sourcemeta::jsonschema::cli::fmt(
1414
const auto options{
1515
parse_options(arguments, {"c", "check", "k", "keep-ordering"})};
1616

17-
for (const auto &entry : for_each_json(options.at(""), parse_ignore(options),
18-
parse_extensions(options))) {
19-
if (entry.first.extension() == ".yaml" ||
20-
entry.first.extension() == ".yml") {
21-
std::cerr << "This command does not support YAML input files yet\n";
17+
for (const auto &entry : for_each_json_or_yaml(options.at(""), options)) {
18+
if (looks_like_yaml(entry.first)) {
19+
log_error() << "This command does not support YAML input files yet\n";
2220
return EXIT_FAILURE;
2321
}
2422

src/command_inspect.cc

+4-7
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
auto sourcemeta::jsonschema::cli::inspect(
1111
const std::span<const std::string> &arguments) -> int {
12-
const auto options{parse_options(arguments, {})};
12+
const auto options{parse_options(arguments, {"h", "http"})};
1313
if (options.at("").size() < 1) {
1414
std::cerr
1515
<< "error: This command expects a path to a schema. For example:\n\n"
@@ -18,17 +18,14 @@ auto sourcemeta::jsonschema::cli::inspect(
1818
}
1919

2020
const sourcemeta::core::JSON schema{
21-
sourcemeta::jsonschema::cli::read_file(options.at("").front())};
21+
read_yaml_or_json(options.at("").front())};
2222

2323
sourcemeta::core::SchemaFrame frame{
2424
sourcemeta::core::SchemaFrame::Mode::Instances};
2525

26-
const auto dialect{default_dialect(options)};
26+
const auto dialect{infer_default_dialect(options)};
2727
frame.analyse(schema, sourcemeta::core::schema_official_walker,
28-
resolver(options,
29-
options.contains("h") || options.contains("http"),
30-
dialect),
31-
dialect);
28+
infer_resolver(options, dialect), dialect);
3229

3330
if (options.contains("json") || options.contains("j")) {
3431
sourcemeta::core::prettify(frame.to_json(), std::cout);

src/command_lint.cc

+6-13
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ static auto disable_lint_rules(sourcemeta::core::SchemaTransformer &bundle,
3131
auto sourcemeta::jsonschema::cli::lint(
3232
const std::span<const std::string> &arguments) -> int {
3333
const auto options{parse_options(
34-
arguments, {"f", "fix", "json", "j", "k", "keep-ordering"})};
34+
arguments, {"f", "fix", "json", "j", "k", "keep-ordering", "h", "http"})};
3535
const bool output_json = options.contains("json") || options.contains("j");
3636

3737
sourcemeta::core::SchemaTransformer bundle;
@@ -63,12 +63,10 @@ auto sourcemeta::jsonschema::cli::lint(
6363

6464
bool result{true};
6565
auto errors_array = sourcemeta::core::JSON::make_array();
66-
const auto dialect{default_dialect(options)};
66+
const auto dialect{infer_default_dialect(options)};
6767

6868
if (options.contains("f") || options.contains("fix")) {
69-
for (const auto &entry :
70-
for_each_json(options.at(""), parse_ignore(options),
71-
parse_extensions(options))) {
69+
for (const auto &entry : for_each_json_or_yaml(options.at(""), options)) {
7270
log_verbose(options) << "Linting: " << entry.first.string() << "\n";
7371
if (entry.first.extension() == ".yaml" ||
7472
entry.first.extension() == ".yml") {
@@ -78,10 +76,7 @@ auto sourcemeta::jsonschema::cli::lint(
7876

7977
auto copy = entry.second;
8078
bundle.apply(copy, sourcemeta::core::schema_official_walker,
81-
resolver(options,
82-
options.contains("h") || options.contains("http"),
83-
dialect),
84-
dialect);
79+
infer_resolver(options, dialect), dialect);
8580
std::ofstream output{entry.first};
8681
if (options.contains("k") || options.contains("keep-ordering")) {
8782
sourcemeta::core::prettify(copy, output);
@@ -92,13 +87,11 @@ auto sourcemeta::jsonschema::cli::lint(
9287
output << "\n";
9388
}
9489
}
95-
for (const auto &entry : for_each_json(options.at(""), parse_ignore(options),
96-
parse_extensions(options))) {
90+
for (const auto &entry : for_each_json_or_yaml(options.at(""), options)) {
9791
log_verbose(options) << "Linting: " << entry.first.string() << "\n";
9892
const bool subresult = bundle.check(
9993
entry.second, sourcemeta::core::schema_official_walker,
100-
resolver(options, options.contains("h") || options.contains("http"),
101-
dialect),
94+
infer_resolver(options, dialect),
10295
[&](const auto &pointer, const auto &name, const auto &message) {
10396
if (output_json) {
10497
auto error_obj = sourcemeta::core::JSON::make_object();

src/command_metaschema.cc

+3-6
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,14 @@ auto sourcemeta::jsonschema::cli::metaschema(
1818
const std::span<const std::string> &arguments) -> int {
1919
const auto options{parse_options(arguments, {"h", "http", "t", "trace"})};
2020
const auto trace{options.contains("t") || options.contains("trace")};
21-
const auto default_dialect_option{default_dialect(options)};
22-
const auto custom_resolver{
23-
resolver(options, options.contains("h") || options.contains("http"),
24-
default_dialect_option)};
21+
const auto default_dialect_option{infer_default_dialect(options)};
22+
const auto custom_resolver{infer_resolver(options, default_dialect_option)};
2523
bool result{true};
2624
sourcemeta::blaze::Evaluator evaluator;
2725

2826
std::map<std::string, sourcemeta::blaze::Template> cache;
2927

30-
for (const auto &entry : for_each_json(options.at(""), parse_ignore(options),
31-
parse_extensions(options))) {
28+
for (const auto &entry : for_each_json_or_yaml(options.at(""), options)) {
3229
if (!sourcemeta::core::is_schema(entry.second)) {
3330
std::cerr << "error: The schema file you provided does not represent a "
3431
"valid JSON Schema\n "

src/command_test.cc

+5-7
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ static auto get_data(const sourcemeta::core::JSON &test_case,
3333
}
3434

3535
try {
36-
return sourcemeta::jsonschema::cli::read_file(data_path);
36+
return sourcemeta::jsonschema::cli::read_yaml_or_json(data_path);
3737
} catch (...) {
3838
std::cout << "\n";
3939
throw;
@@ -44,16 +44,14 @@ auto sourcemeta::jsonschema::cli::test(
4444
const std::span<const std::string> &arguments) -> int {
4545
const auto options{parse_options(arguments, {"h", "http"})};
4646
bool result{true};
47-
const auto dialect{default_dialect(options)};
48-
const auto test_resolver{resolver(
49-
options, options.contains("h") || options.contains("http"), dialect)};
47+
const auto dialect{infer_default_dialect(options)};
48+
const auto test_resolver{infer_resolver(options, dialect)};
5049
const auto verbose{options.contains("verbose") || options.contains("v")};
5150
sourcemeta::blaze::Evaluator evaluator;
5251

53-
for (const auto &entry : for_each_json(options.at(""), parse_ignore(options),
54-
parse_extensions(options))) {
52+
for (const auto &entry : for_each_json_or_yaml(options.at(""), options)) {
5553
const sourcemeta::core::JSON test{
56-
sourcemeta::jsonschema::cli::read_file(entry.first)};
54+
sourcemeta::jsonschema::cli::read_yaml_or_json(entry.first)};
5755
std::cout << entry.first.string() << ":";
5856

5957
if (!test.is_object()) {

src/command_validate.cc

+4-7
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
#include "utils.h"
1616

1717
// TODO: Add a flag to emit output using the standard JSON Schema output format
18-
// TODO: Add a flag to collect annotations
1918
// TODO: Add a flag to take a pre-compiled schema as input
2019
auto sourcemeta::jsonschema::cli::validate(
2120
const std::span<const std::string> &arguments) -> int {
@@ -39,11 +38,10 @@ auto sourcemeta::jsonschema::cli::validate(
3938
}
4039

4140
const auto &schema_path{options.at("").at(0)};
42-
const auto dialect{default_dialect(options)};
43-
const auto custom_resolver{resolver(
44-
options, options.contains("h") || options.contains("http"), dialect)};
41+
const auto dialect{infer_default_dialect(options)};
42+
const auto custom_resolver{infer_resolver(options, dialect)};
4543

46-
const auto schema{sourcemeta::jsonschema::cli::read_file(schema_path)};
44+
const auto schema{read_yaml_or_json(schema_path)};
4745

4846
if (!sourcemeta::core::is_schema(schema)) {
4947
std::cerr << "error: The schema file you provided does not represent a "
@@ -138,8 +136,7 @@ auto sourcemeta::jsonschema::cli::validate(
138136
log_verbose(options) << "warning: The JSONL file is empty\n";
139137
}
140138
} else {
141-
const auto instance{
142-
sourcemeta::jsonschema::cli::read_file(instance_path)};
139+
const auto instance{read_yaml_or_json(instance_path)};
143140
std::ostringstream error;
144141
sourcemeta::blaze::SimpleOutput output{instance};
145142
sourcemeta::blaze::TraceOutput trace_output;

0 commit comments

Comments
 (0)