diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 62cd829fbb..453015d58f 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -324,6 +324,7 @@ add_library( cmInstallTargetGenerator.cxx cmInstallDirectoryGenerator.h cmInstallDirectoryGenerator.cxx + cmJSONHelpers.cxx cmJSONHelpers.h cmJSONState.cxx cmJSONState.h diff --git a/Source/cmJSONHelpers.cxx b/Source/cmJSONHelpers.cxx new file mode 100644 index 0000000000..c36b56d28a --- /dev/null +++ b/Source/cmJSONHelpers.cxx @@ -0,0 +1,113 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#include "cmConfigure.h" // IWYU pragma: keep + +#include "cmJSONHelpers.h" + +#include +#include +#include + +#include + +#include "cmJSONState.h" + +namespace JsonErrors { +ErrorGenerator EXPECTED_TYPE(const std::string& type) +{ + return [type](const Json::Value* value, cmJSONState* state) -> void { + if (state->key().empty()) { + state->AddErrorAtValue(cmStrCat("Expected ", type), value); + return; + } + std::string errMsg = cmStrCat("\"", state->key(), "\" expected ", type); + if (value && value->isConvertibleTo(Json::ValueType::stringValue)) { + errMsg = cmStrCat(errMsg, ", got: ", value->asString()); + } + state->AddErrorAtValue(errMsg, value); + }; +} + +void INVALID_STRING(const Json::Value* value, cmJSONState* state) +{ + JsonErrors::EXPECTED_TYPE("a string")(value, state); +} + +void INVALID_BOOL(const Json::Value* value, cmJSONState* state) +{ + JsonErrors::EXPECTED_TYPE("a bool")(value, state); +} + +void INVALID_INT(const Json::Value* value, cmJSONState* state) +{ + JsonErrors::EXPECTED_TYPE("an integer")(value, state); +} + +void INVALID_UINT(const Json::Value* value, cmJSONState* state) +{ + JsonErrors::EXPECTED_TYPE("an unsigned integer")(value, state); +} + +ObjectErrorGenerator INVALID_NAMED_OBJECT( + const std::function& + nameGenerator) +{ + return [nameGenerator]( + ObjectError errorType, + const Json::Value::Members& extraFields) -> ErrorGenerator { + return [nameGenerator, errorType, extraFields]( + const Json::Value* value, cmJSONState* state) -> void { + std::string name = nameGenerator(value, state); + switch (errorType) { + case ObjectError::RequiredMissing: + state->AddErrorAtValue(cmStrCat("Invalid Required ", name), value); + break; + case ObjectError::InvalidObject: + state->AddErrorAtValue(cmStrCat("Invalid ", name), value); + break; + case ObjectError::ExtraField: { + for (auto const& member : extraFields) { + if (value) { + state->AddErrorAtValue( + cmStrCat("Invalid extra field \"", member, "\" in ", name), + &(*value)[member]); + } else { + state->AddError( + cmStrCat("Invalid extra field \"", member, "\" in ", name)); + } + } + } break; + case ObjectError::MissingRequired: + state->AddErrorAtValue(cmStrCat("Missing required field \"", + state->key(), "\" in ", name), + value); + break; + } + }; + }; +} + +ErrorGenerator INVALID_OBJECT(ObjectError errorType, + const Json::Value::Members& extraFields) +{ + return INVALID_NAMED_OBJECT( + [](const Json::Value*, cmJSONState*) -> std::string { return "Object"; })( + errorType, extraFields); +} + +ErrorGenerator INVALID_NAMED_OBJECT_KEY( + ObjectError errorType, const Json::Value::Members& extraFields) +{ + return INVALID_NAMED_OBJECT( + [](const Json::Value*, cmJSONState* state) -> std::string { + for (auto it = state->parseStack.rbegin(); + it != state->parseStack.rend(); ++it) { + if (it->first.rfind("$vector_item_", 0) == 0) { + continue; + } + return cmStrCat("\"", it->first, "\""); + } + return "root"; + })(errorType, extraFields); +} +} diff --git a/Source/cmJSONHelpers.h b/Source/cmJSONHelpers.h index 5dfb154863..24884ed31a 100644 --- a/Source/cmJSONHelpers.h +++ b/Source/cmJSONHelpers.h @@ -5,11 +5,11 @@ #include "cmConfigure.h" // IWYU pragma: keep #include -#include #include #include #include #include +#include #include #include @@ -18,6 +18,7 @@ #include #include "cmJSONState.h" +#include "cmStringAlgorithms.h" template using cmJSONHelper = @@ -36,94 +37,25 @@ enum ObjectError using ErrorGenerator = std::function; using ObjectErrorGenerator = std::function; -const auto EXPECTED_TYPE = [](const std::string& type) { - return [type](const Json::Value* value, cmJSONState* state) -> void { - if (state->key().empty()) { - state->AddErrorAtValue(cmStrCat("Expected ", type), value); - return; - } - std::string errMsg = cmStrCat("\"", state->key(), "\" expected ", type); - if (value && value->isConvertibleTo(Json::ValueType::stringValue)) { - errMsg = cmStrCat(errMsg, ", got: ", value->asString()); - } - state->AddErrorAtValue(errMsg, value); - }; -}; -const auto INVALID_STRING = [](const Json::Value* value, - cmJSONState* state) -> void { - JsonErrors::EXPECTED_TYPE("a string")(value, state); -}; -const auto INVALID_BOOL = [](const Json::Value* value, - cmJSONState* state) -> void { - JsonErrors::EXPECTED_TYPE("a bool")(value, state); -}; -const auto INVALID_INT = [](const Json::Value* value, - cmJSONState* state) -> void { - JsonErrors::EXPECTED_TYPE("an integer")(value, state); -}; -const auto INVALID_UINT = [](const Json::Value* value, - cmJSONState* state) -> void { - JsonErrors::EXPECTED_TYPE("an unsigned integer")(value, state); -}; -const auto INVALID_NAMED_OBJECT = - [](const std::function& - nameGenerator) -> ObjectErrorGenerator { - return [nameGenerator]( - ObjectError errorType, - const Json::Value::Members& extraFields) -> ErrorGenerator { - return [nameGenerator, errorType, extraFields]( - const Json::Value* value, cmJSONState* state) -> void { - std::string name = nameGenerator(value, state); - switch (errorType) { - case ObjectError::RequiredMissing: - state->AddErrorAtValue(cmStrCat("Invalid Required ", name), value); - break; - case ObjectError::InvalidObject: - state->AddErrorAtValue(cmStrCat("Invalid ", name), value); - break; - case ObjectError::ExtraField: { - for (auto const& member : extraFields) { - if (value) { - state->AddErrorAtValue( - cmStrCat("Invalid extra field \"", member, "\" in ", name), - &(*value)[member]); - } else { - state->AddError( - cmStrCat("Invalid extra field \"", member, "\" in ", name)); - } - } - } break; - case ObjectError::MissingRequired: - state->AddErrorAtValue(cmStrCat("Missing required field \"", - state->key(), "\" in ", name), - value); - break; - } - }; - }; -}; -const auto INVALID_OBJECT = - [](ObjectError errorType, - const Json::Value::Members& extraFields) -> ErrorGenerator { - return INVALID_NAMED_OBJECT( - [](const Json::Value*, cmJSONState*) -> std::string { return "Object"; })( - errorType, extraFields); -}; -const auto INVALID_NAMED_OBJECT_KEY = - [](ObjectError errorType, - const Json::Value::Members& extraFields) -> ErrorGenerator { - return INVALID_NAMED_OBJECT( - [](const Json::Value*, cmJSONState* state) -> std::string { - for (auto it = state->parseStack.rbegin(); - it != state->parseStack.rend(); ++it) { - if (it->first.rfind("$vector_item_", 0) == 0) { - continue; - } - return cmStrCat("\"", it->first, "\""); - } - return "root"; - })(errorType, extraFields); -}; +ErrorGenerator EXPECTED_TYPE(const std::string& type); + +void INVALID_STRING(const Json::Value* value, cmJSONState* state); + +void INVALID_BOOL(const Json::Value* value, cmJSONState* state); + +void INVALID_INT(const Json::Value* value, cmJSONState* state); + +void INVALID_UINT(const Json::Value* value, cmJSONState* state); + +ObjectErrorGenerator INVALID_NAMED_OBJECT( + const std::function& + nameGenerator); + +ErrorGenerator INVALID_OBJECT(ObjectError errorType, + const Json::Value::Members& extraFields); + +ErrorGenerator INVALID_NAMED_OBJECT_KEY( + ObjectError errorType, const Json::Value::Members& extraFields); } struct cmJSONHelperBuilder diff --git a/bootstrap b/bootstrap index 8b43d2092c..39c28bbec2 100755 --- a/bootstrap +++ b/bootstrap @@ -414,6 +414,7 @@ CMAKE_CXX_SOURCES="\ cmInstallTargetGenerator \ cmInstallTargetsCommand \ cmInstalledFile \ + cmJSONHelpers \ cmJSONState \ cmLDConfigLDConfigTool \ cmLDConfigTool \