Skip to content

Commit 059e3f5

Browse files
committed
[WIP] Introduce a new --default-dialect option for most commands
See: #218 Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
1 parent a9ac9ed commit 059e3f5

26 files changed

+348
-31
lines changed

docs/bundle.markdown

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Bundling
55
jsonschema bundle <schema.json|.yaml>
66
[--http/-h] [--verbose/-v] [--resolve/-r <schemas-or-directories> ...]
77
[--extension/-e <extension>] [--ignore/-i <schemas-or-directories>]
8-
[--without-id/-w]
8+
[--without-id/-w] [--default-dialect, -l <uri>]
99
```
1010

1111
A schema may contain references to remote schemas outside the scope of the

docs/decode.markdown

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ Decode
33

44
```sh
55
jsonschema decode <output.binpack> <output.json|.jsonl>
6+
[--default-dialect, -l <uri>]
67
```
78

89
This command decodes a JSON document using [JSON

docs/encode.markdown

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ Encode
33

44
```sh
55
jsonschema encode <document.json|.jsonl> <output.binpack>
6+
[--default-dialect, -l <uri>]
67
```
78

89
This command encodes a JSON document using [JSON

docs/inspect.markdown

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ Framing
33

44
```sh
55
jsonschema inspect <schema.json|.yaml> [--json/-j] [--verbose/-v]
6+
[--default-dialect, -l <uri>]
67
```
78

89
To evaluate a schema, an implementation will first scan it to determine the

docs/lint.markdown

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Linting
55
jsonschema lint [schemas-or-directories...]
66
[--fix/-f] [--json/-j] [--verbose/-v] [--extension/-e <extension>]
77
[--ignore/-i <schemas-or-directories>] [--disable/-d <rule-name>]
8-
[--keep-ordering/-k]
8+
[--keep-ordering/-k] [--default-dialect, -l <uri>]
99
```
1010

1111
JSON Schema is a surprisingly expressive schema language. Like with traditional

docs/metaschema.markdown

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Metaschema
88
jsonschema metaschema [schemas-or-directories...]
99
[--verbose/-v] [--http/-h] [--extension/-e <extension>]
1010
[--ignore/-i <schemas-or-directories>] [--trace/-t]
11+
[--default-dialect, -l <uri>]
1112
```
1213

1314
Ensure that a schema or a set of schemas are considered valid with regards to

docs/test.markdown

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Testing
88
jsonschema test [schemas-or-directories...]
99
[--http/-h] [--verbose/-v] [--resolve/-r <schemas-or-directories> ...]
1010
[--extension/-e <extension>] [--ignore/-i <schemas-or-directories>]
11+
[--default-dialect, -l <uri>]
1112
```
1213

1314
Schemas are code. As such, you should run an automated unit testing suite

docs/validate.markdown

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ Validating
77
```sh
88
jsonschema validate <schema.json|.yaml> <instance.json|.jsonl|.yaml...> [--http/-h]
99
[--verbose/-v] [--resolve/-r <schemas-or-directories> ...] [--benchmark/-b]
10-
[--extension/-e <extension>] [--ignore/-i <schemas-or-directories>] [--trace/-t]
11-
[--fast/-f]
10+
[--extension/-e <extension>] [--ignore/-i <schemas-or-directories>] [--trace/-t]
11+
[--fast/-f] [--default-dialect, -l <uri>]
1212
```
1313

1414
The most popular use case of JSON Schema is to validate JSON documents. The

src/command_bundle.cc

+7-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ 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)};
1415

1516
if (options.at("").size() < 1) {
1617
std::cerr
@@ -23,13 +24,17 @@ auto sourcemeta::jsonschema::cli::bundle(
2324

2425
sourcemeta::core::bundle(
2526
schema, sourcemeta::core::schema_official_walker,
26-
resolver(options, options.contains("h") || options.contains("http")));
27+
resolver(options, options.contains("h") || options.contains("http"),
28+
dialect),
29+
dialect);
2730

2831
if (options.contains("w") || options.contains("without-id")) {
2932
log_verbose(options) << "Removing schema identifiers\n";
3033
sourcemeta::core::unidentify(
3134
schema, sourcemeta::core::schema_official_walker,
32-
resolver(options, options.contains("h") || options.contains("http")));
35+
resolver(options, options.contains("h") || options.contains("http"),
36+
dialect),
37+
dialect);
3338
}
3439

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

src/command_decode.cc

+3-1
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,11 @@ 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)};
4546
sourcemeta::jsonbinpack::compile(
4647
schema, sourcemeta::core::schema_official_walker,
47-
resolver(options, options.contains("h") || options.contains("http")));
48+
resolver(options, options.contains("h") || options.contains("http"),
49+
dialect));
4850
const auto encoding{sourcemeta::jsonbinpack::load(schema)};
4951

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

src/command_encode.cc

+3-1
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,11 @@ 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)};
3233
sourcemeta::jsonbinpack::compile(
3334
schema, sourcemeta::core::schema_official_walker,
34-
resolver(options, options.contains("h") || options.contains("http")));
35+
resolver(options, options.contains("h") || options.contains("http"),
36+
dialect));
3537
const auto encoding{sourcemeta::jsonbinpack::load(schema)};
3638

3739
const std::filesystem::path document{options.at("").front()};

src/command_inspect.cc

+6-1
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,13 @@ auto sourcemeta::jsonschema::cli::inspect(
2222

2323
sourcemeta::core::SchemaFrame frame{
2424
sourcemeta::core::SchemaFrame::Mode::Instances};
25+
26+
const auto dialect{default_dialect(options)};
2527
frame.analyse(schema, sourcemeta::core::schema_official_walker,
26-
resolver(options));
28+
resolver(options,
29+
options.contains("h") || options.contains("http"),
30+
dialect),
31+
dialect);
2732

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

src/command_lint.cc

+9-3
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ auto sourcemeta::jsonschema::cli::lint(
6161

6262
bool result{true};
6363
auto errors_array = sourcemeta::core::JSON::make_array();
64+
const auto dialect{default_dialect(options)};
6465

6566
if (options.contains("f") || options.contains("fix")) {
6667
for (const auto &entry :
@@ -75,7 +76,10 @@ auto sourcemeta::jsonschema::cli::lint(
7576

7677
auto copy = entry.second;
7778
bundle.apply(copy, sourcemeta::core::schema_official_walker,
78-
resolver(options));
79+
resolver(options,
80+
options.contains("h") || options.contains("http"),
81+
dialect),
82+
dialect);
7983
std::ofstream output{entry.first};
8084
if (options.contains("k") || options.contains("keep-ordering")) {
8185
sourcemeta::core::prettify(copy, output);
@@ -91,7 +95,8 @@ auto sourcemeta::jsonschema::cli::lint(
9195
log_verbose(options) << "Linting: " << entry.first.string() << "\n";
9296
const bool subresult = bundle.check(
9397
entry.second, sourcemeta::core::schema_official_walker,
94-
resolver(options),
98+
resolver(options, options.contains("h") || options.contains("http"),
99+
dialect),
95100
[&](const auto &pointer, const auto &name, const auto &message) {
96101
if (output_json) {
97102
auto error_obj = sourcemeta::core::JSON::make_object();
@@ -114,7 +119,8 @@ auto sourcemeta::jsonschema::cli::lint(
114119
sourcemeta::core::stringify(pointer, std::cout);
115120
std::cout << "\"\n";
116121
}
117-
});
122+
},
123+
dialect);
118124

119125
if (!subresult) {
120126
result = false;

src/command_metaschema.cc

+8-5
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ 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)};
2122
const auto custom_resolver{
22-
resolver(options, options.contains("h") || options.contains("http"))};
23+
resolver(options, options.contains("h") || options.contains("http"),
24+
default_dialect_option)};
2325
bool result{true};
2426
sourcemeta::blaze::Evaluator evaluator;
2527

@@ -37,16 +39,17 @@ auto sourcemeta::jsonschema::cli::metaschema(
3739
return EXIT_FAILURE;
3840
}
3941

40-
const auto dialect{sourcemeta::core::dialect(entry.second)};
42+
const auto dialect{
43+
sourcemeta::core::dialect(entry.second, default_dialect_option)};
4144
assert(dialect.has_value());
4245

43-
const auto metaschema{
44-
sourcemeta::core::metaschema(entry.second, custom_resolver)};
46+
const auto metaschema{sourcemeta::core::metaschema(
47+
entry.second, custom_resolver, default_dialect_option)};
4548
if (!cache.contains(dialect.value())) {
4649
const auto metaschema_template{sourcemeta::blaze::compile(
4750
metaschema, sourcemeta::core::schema_official_walker, custom_resolver,
4851
sourcemeta::blaze::default_schema_compiler,
49-
sourcemeta::blaze::Mode::Exhaustive)};
52+
sourcemeta::blaze::Mode::Exhaustive, default_dialect_option)};
5053
cache.insert({dialect.value(), metaschema_template});
5154
}
5255

src/command_test.cc

+5-3
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@ 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 test_resolver{
48-
resolver(options, options.contains("h") || options.contains("http"))};
47+
const auto dialect{default_dialect(options)};
48+
const auto test_resolver{resolver(
49+
options, options.contains("h") || options.contains("http"), dialect)};
4950
const auto verbose{options.contains("verbose") || options.contains("v")};
5051
sourcemeta::blaze::Evaluator evaluator;
5152

@@ -117,7 +118,8 @@ auto sourcemeta::jsonschema::cli::test(
117118
try {
118119
schema_template = sourcemeta::blaze::compile(
119120
schema, sourcemeta::core::schema_official_walker, test_resolver,
120-
sourcemeta::blaze::default_schema_compiler);
121+
sourcemeta::blaze::default_schema_compiler,
122+
sourcemeta::blaze::Mode::FastValidation, dialect);
121123
} catch (const sourcemeta::core::SchemaReferenceError &error) {
122124
if (error.location() == sourcemeta::core::Pointer{"$ref"} &&
123125
error.id() == schema_uri.recompose()) {

src/command_validate.cc

+5-4
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,9 @@ auto sourcemeta::jsonschema::cli::validate(
3939
}
4040

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

4546
const auto schema{sourcemeta::jsonschema::cli::read_file(schema_path)};
4647

@@ -54,14 +55,14 @@ auto sourcemeta::jsonschema::cli::validate(
5455
}
5556

5657
const auto fast_mode{options.contains("f") || options.contains("fast")};
57-
5858
const auto benchmark{options.contains("b") || options.contains("benchmark")};
5959
const auto trace{options.contains("t") || options.contains("trace")};
6060
const auto schema_template{sourcemeta::blaze::compile(
6161
schema, sourcemeta::core::schema_official_walker, custom_resolver,
6262
sourcemeta::blaze::default_schema_compiler,
6363
fast_mode ? sourcemeta::blaze::Mode::FastValidation
64-
: sourcemeta::blaze::Mode::Exhaustive)};
64+
: sourcemeta::blaze::Mode::Exhaustive,
65+
dialect)};
6566
sourcemeta::blaze::Evaluator evaluator;
6667

6768
bool result{true};

src/main.cc

+5-3
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616
constexpr std::string_view USAGE_DETAILS{R"EOF(
1717
Global Options:
1818
19-
--verbose, -v Enable verbose output
20-
--resolve, -r Import the given JSON Schema (or directory of schemas)
21-
into the resolution context
19+
--verbose, -v Enable verbose output
20+
--resolve, -r Import the given JSON Schema (or directory of schemas)
21+
into the resolution context
22+
--default-dialect, -l <uri> Specify the URI for the default dialect to be used
23+
if the `$schema` keyword is not set
2224
2325
Commands:
2426

src/utils.cc

+20-3
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,9 @@ static auto fallback_resolver(
273273
}
274274

275275
auto resolver(const std::map<std::string, std::vector<std::string>> &options,
276-
const bool remote) -> sourcemeta::core::SchemaResolver {
276+
const bool remote,
277+
const std::optional<std::string> &default_dialect)
278+
-> sourcemeta::core::SchemaResolver {
277279
sourcemeta::core::SchemaMapResolver dynamic_resolver{
278280
[remote, &options](std::string_view identifier) {
279281
if (remote) {
@@ -289,7 +291,7 @@ auto resolver(const std::map<std::string, std::vector<std::string>> &options,
289291
parse_extensions(options))) {
290292
log_verbose(options) << "Importing schema into the resolution context: "
291293
<< entry.first.string() << "\n";
292-
dynamic_resolver.add(entry.second);
294+
dynamic_resolver.add(entry.second, default_dialect);
293295
}
294296
}
295297

@@ -299,7 +301,7 @@ auto resolver(const std::map<std::string, std::vector<std::string>> &options,
299301
parse_extensions(options))) {
300302
log_verbose(options) << "Importing schema into the resolution context: "
301303
<< entry.first.string() << "\n";
302-
dynamic_resolver.add(entry.second);
304+
dynamic_resolver.add(entry.second, default_dialect);
303305
}
304306
}
305307

@@ -375,4 +377,19 @@ auto safe_weakly_canonical(const std::filesystem::path &input)
375377
: std::filesystem::weakly_canonical(input);
376378
}
377379

380+
auto default_dialect(
381+
const std::map<std::string, std::vector<std::string>> &options)
382+
-> std::optional<std::string> {
383+
384+
if (options.contains("default-dialect")) {
385+
return options.at("default-dialect").front();
386+
}
387+
388+
if (options.contains("l")) {
389+
return options.at("l").front();
390+
}
391+
392+
return std::nullopt;
393+
}
394+
378395
} // namespace sourcemeta::jsonschema::cli

src/utils.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ auto print(const sourcemeta::blaze::TraceOutput &output, std::ostream &stream)
3737
-> void;
3838

3939
auto resolver(const std::map<std::string, std::vector<std::string>> &options,
40-
const bool remote = false) -> sourcemeta::core::SchemaResolver;
40+
const bool remote,
41+
const std::optional<std::string> &default_dialect)
42+
-> sourcemeta::core::SchemaResolver;
4143

4244
auto log_verbose(const std::map<std::string, std::vector<std::string>> &options)
4345
-> std::ostream &;
@@ -53,6 +55,10 @@ auto parse_ignore(
5355
auto safe_weakly_canonical(const std::filesystem::path &input)
5456
-> std::filesystem::path;
5557

58+
auto default_dialect(
59+
const std::map<std::string, std::vector<std::string>> &options)
60+
-> std::optional<std::string>;
61+
5662
} // namespace sourcemeta::jsonschema::cli
5763

5864
#endif

test/CMakeLists.txt

+6
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ add_jsonschema_test_unix(validate/pass_draft6)
6262
add_jsonschema_test_unix(validate/pass_draft7)
6363
add_jsonschema_test_unix(validate/pass_2019_09)
6464
add_jsonschema_test_unix(validate/pass_2020_12)
65+
add_jsonschema_test_unix(validate/pass_2020_12_default_dialect)
6566
add_jsonschema_test_unix(validate/pass_2020_12_fast)
6667
add_jsonschema_test_unix(validate/fail_draft4)
6768
add_jsonschema_test_unix(validate/fail_draft6)
@@ -101,6 +102,7 @@ add_jsonschema_test_unix(metaschema/fail_non_schema)
101102
add_jsonschema_test_unix(metaschema/pass_cwd)
102103
add_jsonschema_test_unix(metaschema/pass_single)
103104
add_jsonschema_test_unix(metaschema/pass_2020_12)
105+
add_jsonschema_test_unix(metaschema/pass_2020_12_default_dialect)
104106

105107
# Test
106108
add_jsonschema_test_unix(test/fail_resolve_directory_non_schema)
@@ -133,6 +135,7 @@ add_jsonschema_test_unix(test/pass_empty)
133135
add_jsonschema_test_unix(test/pass_empty_verbose)
134136
add_jsonschema_test_unix(test/pass_single_yaml)
135137
add_jsonschema_test_unix(test/pass_single_resolve)
138+
add_jsonschema_test_unix(test/pass_single_resolve_default_dialect)
136139
add_jsonschema_test_unix(test/pass_single_resolve_verbose)
137140
add_jsonschema_test_unix(test/pass_single_resolve_fragment)
138141
add_jsonschema_test_unix(test/pass_single_resolve_fragment_verbose)
@@ -150,6 +153,7 @@ add_jsonschema_test_unix(bundle/pass_resolve_directory)
150153
add_jsonschema_test_unix(bundle/pass_resolve_directory_verbose)
151154
add_jsonschema_test_unix(bundle/pass_resolve_metaschema)
152155
add_jsonschema_test_unix(bundle/pass_resolve_single)
156+
add_jsonschema_test_unix(bundle/pass_resolve_single_default_dialect)
153157
add_jsonschema_test_unix(bundle/pass_resolve_yaml)
154158
add_jsonschema_test_unix(bundle/pass_resolve_with_ignore)
155159
add_jsonschema_test_unix(bundle/pass_without_id)
@@ -165,6 +169,7 @@ add_jsonschema_test_unix(bundle/fail_bigint)
165169

166170
# Inspect
167171
add_jsonschema_test_unix(inspect/pass)
172+
add_jsonschema_test_unix(inspect/pass_default_dialect)
168173
add_jsonschema_test_unix(inspect/pass_yaml)
169174
add_jsonschema_test_unix(inspect/pass_json_output)
170175
add_jsonschema_test_unix(inspect/fail_no_schema)
@@ -176,6 +181,7 @@ add_jsonschema_test_unix(lint/pass_lint_fix)
176181
add_jsonschema_test_unix(lint/pass_lint_fix_keep_ordering)
177182
add_jsonschema_test_unix(lint/pass_lint_no_fix)
178183
add_jsonschema_test_unix(lint/fail_lint)
184+
add_jsonschema_test_unix(lint/fail_lint_default_dialect)
179185
add_jsonschema_test_unix(lint/fail_lint_yaml)
180186
add_jsonschema_test_unix(lint/fail_lint_fix_yaml)
181187
add_jsonschema_test_unix(lint/fail_lint_fix_yml)

0 commit comments

Comments
 (0)