From 728a4b1f2f8cb201e9ba277a28df88dcc2c78ece Mon Sep 17 00:00:00 2001 From: karan-palan Date: Mon, 5 Jan 2026 09:57:12 +0530 Subject: [PATCH 1/3] feat: order lint errors by line number Signed-off-by: karan-palan --- src/command_lint.cc | 50 ++++++++++++++++++++++++++- test/lint/fail_lint_directory_json.sh | 8 ++--- test/lint/fail_lint_json.sh | 8 ++--- 3 files changed, 57 insertions(+), 9 deletions(-) diff --git a/src/command_lint.cc b/src/command_lint.cc index 0fbb4bfa..dc763c5d 100644 --- a/src/command_lint.cc +++ b/src/command_lint.cc @@ -296,6 +296,54 @@ auto sourcemeta::jsonschema::lint(const sourcemeta::core::Options &options) } if (output_json) { + std::vector indices(errors_array.size()); + for (std::size_t i = 0; i < errors_array.size(); ++i) { + indices[i] = i; + } + + std::sort(indices.begin(), indices.end(), + [&errors_array](const std::size_t left_idx, + const std::size_t right_idx) -> bool { + const auto &left = errors_array.at(left_idx); + const auto &right = errors_array.at(right_idx); + + const auto &left_path = left.at("path"); + const auto &right_path = right.at("path"); + if (left_path.to_string() != right_path.to_string()) { + return left_path.to_string() < right_path.to_string(); + } + + const auto &left_pos = left.at("position"); + const auto &right_pos = right.at("position"); + + const bool left_is_null = left_pos.is_null(); + const bool right_is_null = right_pos.is_null(); + if (left_is_null && right_is_null) { + return false; + } + if (left_is_null) { + return false; + } + if (right_is_null) { + return true; + } + + const auto left_line = left_pos.at(0).to_integer(); + const auto right_line = right_pos.at(0).to_integer(); + if (left_line != right_line) { + return left_line < right_line; + } + + const auto left_col = left_pos.at(1).to_integer(); + const auto right_col = right_pos.at(1).to_integer(); + return left_col < right_col; + }); + + auto sorted_errors = sourcemeta::core::JSON::make_array(); + for (const auto idx : indices) { + sorted_errors.push_back(errors_array.at(idx)); + } + auto output_json_object = sourcemeta::core::JSON::make_object(); output_json_object.assign("valid", sourcemeta::core::JSON{result}); @@ -308,7 +356,7 @@ auto sourcemeta::jsonschema::lint(const sourcemeta::core::Options &options) "health", sourcemeta::core::JSON{static_cast(health)}); } - output_json_object.assign("errors", sourcemeta::core::JSON{errors_array}); + output_json_object.assign("errors", sourcemeta::core::JSON{sorted_errors}); sourcemeta::core::prettify(output_json_object, std::cout, indentation); std::cout << "\n"; } diff --git a/test/lint/fail_lint_directory_json.sh b/test/lint/fail_lint_directory_json.sh index 7a0b6ee0..ef59b2c6 100755 --- a/test/lint/fail_lint_directory_json.sh +++ b/test/lint/fail_lint_directory_json.sh @@ -42,16 +42,16 @@ cat << EOF > "$TMP/expected.json" "id": "enum_with_type", "message": "Setting \`type\` alongside \`enum\` is considered an anti-pattern, as the enumeration choices already imply their respective types", "description": null, - "schemaLocation": "/enum", - "position": [ 7, 3, 7, 33 ] + "schemaLocation": "/type", + "position": [ 6, 3, 6, 18 ] }, { "path": "$(realpath "$TMP")/schemas/foo.json", "id": "enum_with_type", "message": "Setting \`type\` alongside \`enum\` is considered an anti-pattern, as the enumeration choices already imply their respective types", "description": null, - "schemaLocation": "/type", - "position": [ 6, 3, 6, 18 ] + "schemaLocation": "/enum", + "position": [ 7, 3, 7, 33 ] } ] } diff --git a/test/lint/fail_lint_json.sh b/test/lint/fail_lint_json.sh index 31e00624..2fbc7a93 100755 --- a/test/lint/fail_lint_json.sh +++ b/test/lint/fail_lint_json.sh @@ -30,16 +30,16 @@ cat << EOF > "$TMP/expected.json" "id": "enum_with_type", "message": "Setting \`type\` alongside \`enum\` is considered an anti-pattern, as the enumeration choices already imply their respective types", "description": null, - "schemaLocation": "/enum", - "position": [ 6, 3, 6, 19 ] + "schemaLocation": "/type", + "position": [ 5, 3, 5, 18 ] }, { "path": "$(realpath "$TMP")/schema.json", "id": "enum_with_type", "message": "Setting \`type\` alongside \`enum\` is considered an anti-pattern, as the enumeration choices already imply their respective types", "description": null, - "schemaLocation": "/type", - "position": [ 5, 3, 5, 18 ] + "schemaLocation": "/enum", + "position": [ 6, 3, 6, 19 ] } ] } From cbf8062d1eeba786e22cc820c47af0ae9ad6982e Mon Sep 17 00:00:00 2001 From: karan-palan Date: Mon, 5 Jan 2026 18:26:40 +0530 Subject: [PATCH 2/3] simply logic by using json array Signed-off-by: karan-palan --- src/command_lint.cc | 51 +++++++++++---------------------------------- 1 file changed, 12 insertions(+), 39 deletions(-) diff --git a/src/command_lint.cc b/src/command_lint.cc index dc763c5d..05bab696 100644 --- a/src/command_lint.cc +++ b/src/command_lint.cc @@ -296,54 +296,27 @@ auto sourcemeta::jsonschema::lint(const sourcemeta::core::Options &options) } if (output_json) { - std::vector indices(errors_array.size()); - for (std::size_t i = 0; i < errors_array.size(); ++i) { - indices[i] = i; - } - - std::sort(indices.begin(), indices.end(), - [&errors_array](const std::size_t left_idx, - const std::size_t right_idx) -> bool { - const auto &left = errors_array.at(left_idx); - const auto &right = errors_array.at(right_idx); - - const auto &left_path = left.at("path"); - const auto &right_path = right.at("path"); - if (left_path.to_string() != right_path.to_string()) { - return left_path.to_string() < right_path.to_string(); + std::sort(errors_array.as_array().begin(), errors_array.as_array().end(), + [](const sourcemeta::core::JSON &left, + const sourcemeta::core::JSON &right) { + const auto left_path_str = left.at("path").to_string(); + const auto right_path_str = right.at("path").to_string(); + if (left_path_str != right_path_str) { + return left_path_str < right_path_str; } const auto &left_pos = left.at("position"); const auto &right_pos = right.at("position"); - const bool left_is_null = left_pos.is_null(); - const bool right_is_null = right_pos.is_null(); - if (left_is_null && right_is_null) { + if (left_pos.is_null()) return false; - } - if (left_is_null) { - return false; - } - if (right_is_null) { + if (right_pos.is_null()) return true; - } - - const auto left_line = left_pos.at(0).to_integer(); - const auto right_line = right_pos.at(0).to_integer(); - if (left_line != right_line) { - return left_line < right_line; - } - const auto left_col = left_pos.at(1).to_integer(); - const auto right_col = right_pos.at(1).to_integer(); - return left_col < right_col; + return left_pos.front().to_integer() < + right_pos.front().to_integer(); }); - auto sorted_errors = sourcemeta::core::JSON::make_array(); - for (const auto idx : indices) { - sorted_errors.push_back(errors_array.at(idx)); - } - auto output_json_object = sourcemeta::core::JSON::make_object(); output_json_object.assign("valid", sourcemeta::core::JSON{result}); @@ -356,7 +329,7 @@ auto sourcemeta::jsonschema::lint(const sourcemeta::core::Options &options) "health", sourcemeta::core::JSON{static_cast(health)}); } - output_json_object.assign("errors", sourcemeta::core::JSON{sorted_errors}); + output_json_object.assign("errors", sourcemeta::core::JSON{errors_array}); sourcemeta::core::prettify(output_json_object, std::cout, indentation); std::cout << "\n"; } From ad1266d0c1576187f72db9c8dd5c9fe72f55df98 Mon Sep 17 00:00:00 2001 From: karan-palan Date: Tue, 6 Jan 2026 09:46:55 +0530 Subject: [PATCH 3/3] sort based on line numbers Signed-off-by: karan-palan --- src/command_lint.cc | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/src/command_lint.cc b/src/command_lint.cc index 05bab696..fbb2e262 100644 --- a/src/command_lint.cc +++ b/src/command_lint.cc @@ -299,22 +299,8 @@ auto sourcemeta::jsonschema::lint(const sourcemeta::core::Options &options) std::sort(errors_array.as_array().begin(), errors_array.as_array().end(), [](const sourcemeta::core::JSON &left, const sourcemeta::core::JSON &right) { - const auto left_path_str = left.at("path").to_string(); - const auto right_path_str = right.at("path").to_string(); - if (left_path_str != right_path_str) { - return left_path_str < right_path_str; - } - - const auto &left_pos = left.at("position"); - const auto &right_pos = right.at("position"); - - if (left_pos.is_null()) - return false; - if (right_pos.is_null()) - return true; - - return left_pos.front().to_integer() < - right_pos.front().to_integer(); + return left.at("position").front() < + right.at("position").front(); }); auto output_json_object = sourcemeta::core::JSON::make_object();