Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 16 additions & 17 deletions src/command_fmt.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,22 @@ auto sourcemeta::jsonschema::fmt(const sourcemeta::core::Options &options)
std::vector<std::string> failed_files;
const auto indentation{parse_indentation(options)};
for (const auto &entry : for_each_json(options)) {
const auto &path{entry.local_path_or_throw("fmt")};
if (entry.yaml) {
throw YAMLInputError{"This command does not support YAML input files yet",
entry.first};
path};
}

if (options.contains("check")) {
LOG_VERBOSE(options) << "Checking: " << entry.first.string() << "\n";
LOG_VERBOSE(options) << "Checking: " << path.string() << "\n";
} else {
LOG_VERBOSE(options) << "Formatting: " << entry.first.string() << "\n";
LOG_VERBOSE(options) << "Formatting: " << path.string() << "\n";
}

try {
const auto configuration_path{find_configuration(entry.first)};
const auto configuration_path{find_configuration(path)};
const auto &configuration{
read_configuration(options, configuration_path, entry.first)};
read_configuration(options, configuration_path, path)};
const auto dialect{default_dialect(options, configuration)};
const auto &custom_resolver{
resolver(options, options.contains("http"), dialect, configuration)};
Expand All @@ -51,39 +52,37 @@ auto sourcemeta::jsonschema::fmt(const sourcemeta::core::Options &options)
}
expected << "\n";

std::ifstream current_stream{entry.first};
std::ifstream current_stream{path};
std::ostringstream current;
current << current_stream.rdbuf();

if (options.contains("check")) {
if (current.str() == expected.str()) {
LOG_VERBOSE(options) << "ok: " << entry.first.string() << "\n";
LOG_VERBOSE(options) << "ok: " << path.string() << "\n";
} else if (output_json) {
failed_files.push_back(entry.first.string());
failed_files.push_back(path.string());
result = false;
} else {
std::cerr << "fail: " << entry.first.string() << "\n";
std::cerr << "fail: " << path.string() << "\n";
result = false;
}
} else {
if (current.str() != expected.str()) {
std::ofstream output{entry.first};
std::ofstream output{path};
output << expected.str();
}
}
} catch (const sourcemeta::core::SchemaRelativeMetaschemaResolutionError
&error) {
throw FileError<
sourcemeta::core::SchemaRelativeMetaschemaResolutionError>(
entry.first, error);
sourcemeta::core::SchemaRelativeMetaschemaResolutionError>(path,
error);
} catch (const sourcemeta::core::SchemaResolutionError &error) {
throw FileError<sourcemeta::core::SchemaResolutionError>(entry.first,
error);
throw FileError<sourcemeta::core::SchemaResolutionError>(path, error);
} catch (const sourcemeta::core::SchemaUnknownBaseDialectError &) {
throw FileError<sourcemeta::core::SchemaUnknownBaseDialectError>(
entry.first);
throw FileError<sourcemeta::core::SchemaUnknownBaseDialectError>(path);
} catch (const sourcemeta::core::SchemaError &error) {
throw FileError<sourcemeta::core::SchemaError>(entry.first, error.what());
throw FileError<sourcemeta::core::SchemaError>(path, error.what());
}
}

Expand Down
62 changes: 39 additions & 23 deletions src/command_lint.cc
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ static auto get_lint_callback(sourcemeta::core::JSON &errors_array,
if (output_json) {
auto error_obj = sourcemeta::core::JSON::make_object();

error_obj.assign("path", sourcemeta::core::JSON{entry.first.string()});
error_obj.assign("path", sourcemeta::core::JSON{entry.first});
error_obj.assign("id", sourcemeta::core::JSON{name});
error_obj.assign("message", sourcemeta::core::JSON{message});
error_obj.assign("description",
Expand All @@ -88,7 +88,11 @@ static auto get_lint_callback(sourcemeta::core::JSON &errors_array,

errors_array.push_back(error_obj);
} else {
std::cout << std::filesystem::relative(entry.first).string();
if (entry.path.has_value()) {
std::cout << std::filesystem::relative(entry.path.value()).string();
} else {
std::cout << entry.first;
}
if (position.has_value()) {
std::cout << ":";
std::cout << std::get<0>(position.value());
Expand Down Expand Up @@ -184,18 +188,18 @@ auto sourcemeta::jsonschema::lint(const sourcemeta::core::Options &options)

if (options.contains("fix")) {
for (const auto &entry : for_each_json(options)) {
const auto configuration_path{find_configuration(entry.first)};
const auto &path{entry.local_path_or_throw("lint --fix")};
const auto configuration_path{find_configuration(path)};
const auto &configuration{
read_configuration(options, configuration_path, entry.first)};
read_configuration(options, configuration_path, path)};
const auto dialect{default_dialect(options, configuration)};

const auto &custom_resolver{
resolver(options, options.contains("http"), dialect, configuration)};
LOG_VERBOSE(options) << "Linting: " << entry.first.string() << "\n";
LOG_VERBOSE(options) << "Linting: " << entry.first << "\n";
if (entry.yaml) {
throw YAMLInputError{
"The --fix option is not supported for YAML input files",
entry.first};
"The --fix option is not supported for YAML input files", path};
}

auto copy = entry.second;
Expand All @@ -206,7 +210,7 @@ auto sourcemeta::jsonschema::lint(const sourcemeta::core::Options &options)
const auto apply_result = bundle.apply(
copy, sourcemeta::core::schema_walker, custom_resolver,
get_lint_callback(errors_array, entry, output_json), dialect,
sourcemeta::core::URI::from_path(entry.first).recompose());
entry.base_uri());
scores.emplace_back(apply_result.second);
if (!apply_result.first) {
return 2;
Expand All @@ -216,20 +220,19 @@ auto sourcemeta::jsonschema::lint(const sourcemeta::core::Options &options)
} catch (
const sourcemeta::core::SchemaTransformRuleProcessedTwiceError
&error) {
throw LintAutoFixError{error.what(), entry.first,
error.location()};
throw LintAutoFixError{error.what(), path, error.location()};
} catch (
const sourcemeta::core::SchemaBrokenReferenceError &error) {
throw LintAutoFixError{
"Could not autofix the schema without breaking its internal "
"references",
entry.first, error.location()};
path, error.location()};
} catch (const sourcemeta::core::SchemaUnknownBaseDialectError &) {
throw FileError<sourcemeta::core::SchemaUnknownBaseDialectError>(
entry.first);
path);
} catch (const sourcemeta::core::SchemaResolutionError &error) {
throw FileError<sourcemeta::core::SchemaResolutionError>(
entry.first, error);
throw FileError<sourcemeta::core::SchemaResolutionError>(path,
error);
}
});

Expand All @@ -239,7 +242,7 @@ auto sourcemeta::jsonschema::lint(const sourcemeta::core::Options &options)
}

if (copy != entry.second) {
std::ofstream output{entry.first};
std::ofstream output{path};
sourcemeta::core::prettify(copy, output, indentation);
output << "\n";
}
Expand All @@ -250,13 +253,17 @@ auto sourcemeta::jsonschema::lint(const sourcemeta::core::Options &options)
}
} else {
for (const auto &entry : for_each_json(options)) {
const auto configuration_path{find_configuration(entry.first)};
const bool is_remote{!entry.path.has_value()};
const auto configuration_path{find_configuration(
is_remote ? std::filesystem::current_path() : entry.path.value())};
const auto &configuration{
read_configuration(options, configuration_path, entry.first)};
is_remote ? read_configuration(options, configuration_path)
: read_configuration(options, configuration_path,
entry.path.value())};
const auto dialect{default_dialect(options, configuration)};
const auto &custom_resolver{
resolver(options, options.contains("http"), dialect, configuration)};
LOG_VERBOSE(options) << "Linting: " << entry.first.string() << "\n";
LOG_VERBOSE(options) << "Linting: " << entry.first << "\n";

const auto wrapper_result =
sourcemeta::jsonschema::try_catch(options, [&]() {
Expand All @@ -265,7 +272,7 @@ auto sourcemeta::jsonschema::lint(const sourcemeta::core::Options &options)
entry.second, sourcemeta::core::schema_walker,
custom_resolver,
get_lint_callback(errors_array, entry, output_json), dialect,
sourcemeta::core::URI::from_path(entry.first).recompose());
entry.base_uri());
scores.emplace_back(subresult.second);
if (subresult.first) {
return EXIT_SUCCESS;
Expand All @@ -274,11 +281,20 @@ auto sourcemeta::jsonschema::lint(const sourcemeta::core::Options &options)
return 2;
}
} catch (const sourcemeta::core::SchemaUnknownBaseDialectError &) {
throw FileError<sourcemeta::core::SchemaUnknownBaseDialectError>(
entry.first);
if (entry.path.has_value()) {
throw FileError<
sourcemeta::core::SchemaUnknownBaseDialectError>(
entry.path.value());
}

throw;
} catch (const sourcemeta::core::SchemaResolutionError &error) {
throw FileError<sourcemeta::core::SchemaResolutionError>(
entry.first, error);
if (entry.path.has_value()) {
throw FileError<sourcemeta::core::SchemaResolutionError>(
entry.path.value(), error);
}

throw;
}
});

Expand Down
120 changes: 82 additions & 38 deletions src/command_metaschema.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@
#include <sourcemeta/blaze/evaluator.h>
#include <sourcemeta/blaze/output.h>

#include <cassert> // assert
#include <cassert> // assert
#include <filesystem>
#include <iostream> // std::cerr
#include <map> // std::map
#include <string> // std::string
#include <optional>
#include <sstream>
#include <string> // std::string
#include <string_view>
#include <vector>

#include "command.h"
#include "configuration.h"
Expand All @@ -29,31 +34,43 @@ auto sourcemeta::jsonschema::metaschema(
sourcemeta::blaze::Evaluator evaluator;

std::map<std::string, sourcemeta::blaze::Template> cache;
const auto current_path{std::filesystem::current_path()};
const auto remote_configuration_path{find_configuration(current_path)};
const auto &remote_configuration{
read_configuration(options, remote_configuration_path)};

for (const auto &entry : for_each_json(options)) {
if (!sourcemeta::core::is_schema(entry.second)) {
throw NotSchemaError{entry.first};
}

const auto configuration_path{find_configuration(entry.first)};
const auto &configuration{
read_configuration(options, configuration_path, entry.first)};
const auto default_dialect_option{default_dialect(options, configuration)};
const auto process_schema =
[&](const sourcemeta::core::JSON &schema,
const sourcemeta::core::PointerPositionTracker &positions,
const std::optional<std::filesystem::path> &schema_path,
const std::string_view schema_display,
const sourcemeta::jsonschema::CustomResolver &custom_resolver,
const std::string_view default_dialect_option) -> void {
if (!sourcemeta::core::is_schema(schema)) {
if (schema_path.has_value()) {
throw NotSchemaError{schema_path.value()};
}

const auto &custom_resolver{resolver(options, options.contains("http"),
default_dialect_option,
configuration)};
throw RemoteSchemaNotSchemaError{std::string{schema_display}};
}

try {
const auto dialect{
sourcemeta::core::dialect(entry.second, default_dialect_option)};
sourcemeta::core::dialect(schema, default_dialect_option)};
if (dialect.empty()) {
throw FileError<sourcemeta::core::SchemaUnknownBaseDialectError>(
entry.first);
if (schema_path.has_value()) {
throw FileError<sourcemeta::core::SchemaUnknownBaseDialectError>(
schema_path.value());
}

std::ostringstream error;
error << "Could not resolve the metaschema of the schema\n at uri "
<< schema_display;
throw std::runtime_error(error.str());
}

const auto metaschema{sourcemeta::core::metaschema(
entry.second, custom_resolver, default_dialect_option)};
schema, custom_resolver, default_dialect_option)};
const sourcemeta::core::JSON bundled{
sourcemeta::core::bundle(metaschema, sourcemeta::core::schema_walker,
custom_resolver, default_dialect_option)};
Expand All @@ -74,16 +91,16 @@ auto sourcemeta::jsonschema::metaschema(
sourcemeta::blaze::TraceOutput output{
sourcemeta::core::schema_walker, custom_resolver,
sourcemeta::core::empty_weak_pointer, frame};
result = evaluator.validate(cache.at(std::string{dialect}),
entry.second, std::ref(output));
print(output, entry.positions, std::cout);
result = evaluator.validate(cache.at(std::string{dialect}), schema,
std::ref(output));
print(output, positions, std::cout);
} else if (json_output) {
// Otherwise its impossible to correlate the output
// when validating i.e. a directory of schemas
std::cerr << entry.first.string() << "\n";
std::cerr << schema_display << "\n";
const auto output{sourcemeta::blaze::standard(
evaluator, cache.at(std::string{dialect}), entry.second,
sourcemeta::blaze::StandardOutput::Basic, entry.positions)};
evaluator, cache.at(std::string{dialect}), schema,
sourcemeta::blaze::StandardOutput::Basic, positions)};
assert(output.is_object());
assert(output.defines("valid"));
assert(output.at("valid").is_boolean());
Expand All @@ -94,29 +111,56 @@ auto sourcemeta::jsonschema::metaschema(
sourcemeta::core::prettify(output, std::cout);
std::cout << "\n";
} else {
sourcemeta::blaze::SimpleOutput output{entry.second};
if (evaluator.validate(cache.at(std::string{dialect}), entry.second,
sourcemeta::blaze::SimpleOutput output{schema};
if (evaluator.validate(cache.at(std::string{dialect}), schema,
std::ref(output))) {
LOG_VERBOSE(options)
<< "ok: "
<< sourcemeta::core::weakly_canonical(entry.first).string()
<< "\n matches " << dialect << "\n";
<< "ok: " << schema_display << "\n matches " << dialect << "\n";
} else {
std::cerr << "fail: "
<< sourcemeta::core::weakly_canonical(entry.first).string()
<< "\n";
print(output, entry.positions, std::cerr);
std::cerr << "fail: " << schema_display << "\n";
print(output, positions, std::cerr);
result = false;
}
}
} catch (const sourcemeta::core::SchemaRelativeMetaschemaResolutionError
&error) {
throw FileError<
sourcemeta::core::SchemaRelativeMetaschemaResolutionError>(
entry.first, error);
if (schema_path.has_value()) {
throw FileError<
sourcemeta::core::SchemaRelativeMetaschemaResolutionError>(
schema_path.value(), error);
}

throw;
} catch (const sourcemeta::core::SchemaResolutionError &error) {
throw FileError<sourcemeta::core::SchemaResolutionError>(entry.first,
error);
if (schema_path.has_value()) {
throw FileError<sourcemeta::core::SchemaResolutionError>(
schema_path.value(), error);
}

throw;
}
};

for (const auto &entry : for_each_json(options)) {
if (entry.path.has_value()) {
const auto configuration_path{find_configuration(entry.path.value())};
const auto &configuration{
read_configuration(options, configuration_path, entry.path.value())};
const auto default_dialect_option{
default_dialect(options, configuration)};
const auto &custom_resolver{resolver(options, options.contains("http"),
default_dialect_option,
configuration)};
process_schema(entry.second, entry.positions, entry.path, entry.first,
custom_resolver, default_dialect_option);
} else {
const auto remote_default_dialect_option{
default_dialect(options, remote_configuration)};
const auto &remote_resolver{resolver(options, options.contains("http"),
remote_default_dialect_option,
remote_configuration)};
process_schema(entry.second, entry.positions, std::nullopt, entry.first,
remote_resolver, remote_default_dialect_option);
}
}

Expand Down
Loading