geode/loader/src/utils/JsonValidation.cpp

329 lines
8.8 KiB
C++
Raw Normal View History

2022-10-23 09:22:27 -04:00
#include <Geode/utils/JsonValidation.hpp>
using namespace geode::prelude;
2022-10-23 09:22:27 -04:00
2023-02-08 10:25:07 -05:00
matjson::Value& JsonMaybeSomething::json() {
2022-10-23 09:22:27 -04:00
return m_json;
}
2023-02-08 10:25:07 -05:00
JsonMaybeSomething::JsonMaybeSomething(
JsonChecker& checker, matjson::Value& json, std::string const& hierarchy, bool hasValue
2022-10-30 14:56:36 -04:00
) :
m_checker(checker),
m_json(json), m_hierarchy(hierarchy), m_hasValue(hasValue) {}
2023-02-08 10:25:07 -05:00
bool JsonMaybeSomething::isError() const {
2022-10-23 09:22:27 -04:00
return m_checker.isError() || !m_hasValue;
}
2023-02-08 10:25:07 -05:00
std::string JsonMaybeSomething::getError() const {
return m_checker.getError();
}
2023-02-08 10:25:07 -05:00
JsonMaybeSomething::operator bool() const {
2022-10-23 09:22:27 -04:00
return !isError();
}
2023-02-08 10:25:07 -05:00
void JsonMaybeSomething::setError(std::string const& error) {
2022-10-23 09:22:27 -04:00
m_checker.m_result = error;
}
2023-02-08 10:25:07 -05:00
JsonMaybeValue::JsonMaybeValue(
JsonChecker& checker, matjson::Value& json, std::string const& hierarchy, bool hasValue
2022-10-30 14:56:36 -04:00
) :
2023-02-08 10:25:07 -05:00
JsonMaybeSomething(checker, json, hierarchy, hasValue) {}
2022-10-23 09:22:27 -04:00
2023-02-08 10:25:07 -05:00
JsonMaybeSomething& JsonMaybeValue::self() {
return *static_cast<JsonMaybeSomething*>(this);
2022-10-23 09:22:27 -04:00
}
// template<class Json>
// template<nlohmann::detail::value_t T>
2023-02-08 10:25:07 -05:00
// JsonMaybeValue& JsonMaybeValue::as() {
2022-10-23 09:22:27 -04:00
// if (this->isError()) return *this;
// if (!jsonConvertibleTo(self().m_json.type(), T)) {
// this->setError(
2022-10-30 14:56:36 -04:00
// self().m_hierarchy + ": Invalid type \"" +
// self().m_json.type_name() + "\", expected \"" +
2022-10-23 09:22:27 -04:00
// jsonValueTypeToString(T) + "\""
// );
// }
// m_inferType = false;
// return *this;
// }
2023-02-08 10:25:07 -05:00
JsonMaybeValue& JsonMaybeValue::array() {
this->as<value_t::Array>();
2022-10-23 09:22:27 -04:00
return *this;
}
// template<class Json>
// template<nlohmann::detail::value_t... T>
2023-02-08 10:25:07 -05:00
// JsonMaybeValue JsonMaybeValue::asOneOf() {
2022-10-23 09:22:27 -04:00
// if (this->isError()) return *this;
// bool isOneOf = (... || jsonConvertibleTo(self().m_json.type(), T));
// if (!isOneOf) {
// this->setError(
2022-10-30 14:56:36 -04:00
// self().m_hierarchy + ": Invalid type \"" +
// self().m_json.type_name() + "\", expected one of \"" +
2022-10-23 09:22:27 -04:00
// (jsonValueTypeToString(T), ...) + "\""
// );
// }
// m_inferType = false;
// return *this;
// }
// template<class Json>
// template<nlohmann::detail::value_t T>
2023-02-08 10:25:07 -05:00
// JsonMaybeValue JsonMaybeValue::is() {
2022-10-23 09:22:27 -04:00
// if (this->isError()) return *this;
// self().m_hasValue = jsonConvertibleTo(self().m_json.type(), T);
// m_inferType = false;
// return *this;
// }
// template<class Json>
// template<class T>
2023-02-08 10:25:07 -05:00
// JsonMaybeValue JsonMaybeValue::validate(JsonValueValidator<T> validator) {
2022-10-23 09:22:27 -04:00
// if (this->isError()) return *this;
// try {
// if (!validator(self().m_json.template get<T>())) {
// this->setError(self().m_hierarchy + ": Invalid value format");
// }
// } catch(...) {
// this->setError(
// self().m_hierarchy + ": Invalid type \"" +
// std::string(self().m_json.type_name()) + "\""
// );
// }
// return *this;
// }
// template<class Json>
// template<class T>
2023-02-08 10:25:07 -05:00
// JsonMaybeValue JsonMaybeValue::inferType() {
2022-10-23 09:22:27 -04:00
// if (this->isError() || !m_inferType) return *this;
// return this->as<getJsonType<T>()>();
// }
// template<class Json>
// template<class T>
2023-02-08 10:25:07 -05:00
// JsonMaybeValue JsonMaybeValue::intoRaw(T& target) {
2022-10-23 09:22:27 -04:00
// if (this->isError()) return *this;
// target = self().m_json;
// return *this;
// }
// template<class Json>
// template<class T>
2023-02-08 10:25:07 -05:00
// JsonMaybeValue JsonMaybeValue::into(T& target) {
2022-10-23 09:22:27 -04:00
// return this->intoAs<T, T>(target);
// }
// template<class Json>
// template<class T>
2023-02-08 10:25:07 -05:00
// JsonMaybeValue JsonMaybeValue::into(std::optional<T>& target) {
2022-10-23 09:22:27 -04:00
// return this->intoAs<T, std::optional<T>>(target);
// }
// template<class Json>
// template<class A, class T>
2023-02-08 10:25:07 -05:00
// JsonMaybeValue JsonMaybeValue::intoAs(T& target) {
2022-10-23 09:22:27 -04:00
// this->inferType<A>();
// if (this->isError()) return *this;
// try {
// target = self().m_json.template get<A>();
// } catch(...) {
// this->setError(
2022-10-30 14:56:36 -04:00
// self().m_hierarchy + ": Invalid type \"" +
2022-10-23 09:22:27 -04:00
// std::string(self().m_json.type_name()) + "\""
// );
// }
// return *this;
// }
// template<class Json>
// template<class T>
2023-02-08 10:25:07 -05:00
// T JsonMaybeValue::get() {
2022-10-23 09:22:27 -04:00
// this->inferType<T>();
// if (this->isError()) return T();
// try {
// return self().m_json.template get<T>();
// } catch(...) {
// this->setError(
2022-10-30 14:56:36 -04:00
// self().m_hierarchy + ": Invalid type to get \"" +
2022-10-23 09:22:27 -04:00
// std::string(self().m_json.type_name()) + "\""
// );
// }
// return T();
// }
2023-02-08 10:25:07 -05:00
JsonMaybeObject JsonMaybeValue::obj() {
this->as<value_t::Object>();
2022-10-30 14:56:36 -04:00
return JsonMaybeObject(self().m_checker, self().m_json, self().m_hierarchy, self().m_hasValue);
2022-10-23 09:22:27 -04:00
}
// template<class Json>
// template<class T>
2023-02-08 10:25:07 -05:00
// struct JsonMaybeValue::Iterator {
2022-10-23 09:22:27 -04:00
// std::vector<T> m_values;
// using iterator = typename std::vector<T>::iterator;
// using const_iterator = typename std::vector<T>::const_iterator;
// iterator begin() {
// return m_values.begin();
// }
// iterator end() {
// return m_values.end();
// }
// const_iterator begin() const {
// return m_values.begin();
// }
// const_iterator end() const {
// return m_values.end();
// }
// };
2023-02-08 10:25:07 -05:00
JsonMaybeValue JsonMaybeValue::at(size_t i) {
this->as<value_t::Array>();
2022-10-23 09:22:27 -04:00
if (this->isError()) return *this;
auto& json = self().m_json.as_array();
if (json.size() <= i) {
2022-10-23 09:22:27 -04:00
this->setError(
self().m_hierarchy + ": has " + std::to_string(json.size()) +
2022-10-30 14:56:36 -04:00
"items "
", expected to have at least " +
std::to_string(i + 1)
2022-10-23 09:22:27 -04:00
);
return *this;
}
2023-02-08 10:25:07 -05:00
return JsonMaybeValue(
self().m_checker, json.at(i), self().m_hierarchy + "." + std::to_string(i), self().m_hasValue
2022-10-23 09:22:27 -04:00
);
}
2023-02-08 10:25:07 -05:00
typename JsonMaybeValue::template Iterator<JsonMaybeValue> JsonMaybeValue::iterate() {
this->as<value_t::Array>();
2023-02-08 10:25:07 -05:00
Iterator<JsonMaybeValue> iter;
2022-10-23 09:22:27 -04:00
if (this->isError()) return iter;
auto& json = self().m_json.as_array();
2022-10-23 09:22:27 -04:00
size_t i = 0;
for (auto& obj : json) {
2022-10-23 09:22:27 -04:00
iter.m_values.emplace_back(
2022-10-30 14:56:36 -04:00
self().m_checker, obj, self().m_hierarchy + "." + std::to_string(i++), self().m_hasValue
2022-10-23 09:22:27 -04:00
);
}
return iter;
}
2023-02-08 10:25:07 -05:00
typename JsonMaybeValue::template Iterator<std::pair<std::string, JsonMaybeValue>> JsonMaybeValue::items() {
this->as<value_t::Object>();
2023-02-08 10:25:07 -05:00
Iterator<std::pair<std::string, JsonMaybeValue>> iter;
2022-10-23 09:22:27 -04:00
if (this->isError()) return iter;
for (auto& [k, v] : self().m_json.as_object()) {
2022-10-30 14:56:36 -04:00
iter.m_values.emplace_back(
k,
2023-02-08 10:25:07 -05:00
JsonMaybeValue(self().m_checker, v, self().m_hierarchy + "." + k, self().m_hasValue)
2022-10-30 14:56:36 -04:00
);
2022-10-23 09:22:27 -04:00
}
return iter;
}
2023-02-08 10:25:07 -05:00
JsonMaybeObject::JsonMaybeObject(
JsonChecker& checker, matjson::Value& json, std::string const& hierarchy, bool hasValue
2022-10-30 14:56:36 -04:00
) :
2023-02-08 10:25:07 -05:00
JsonMaybeSomething(checker, json, hierarchy, hasValue) {}
2022-10-23 09:22:27 -04:00
2023-02-08 10:25:07 -05:00
JsonMaybeSomething& JsonMaybeObject::self() {
return *static_cast<JsonMaybeSomething*>(this);
2022-10-23 09:22:27 -04:00
}
2023-02-08 10:25:07 -05:00
void JsonMaybeObject::addKnownKey(std::string const& key) {
2022-10-23 09:22:27 -04:00
m_knownKeys.insert(key);
}
2023-02-08 10:25:07 -05:00
matjson::Value& JsonMaybeObject::json() {
2022-10-23 09:22:27 -04:00
return self().m_json;
}
2023-02-08 10:25:07 -05:00
JsonMaybeValue JsonMaybeObject::emptyValue() {
2022-10-23 09:22:27 -04:00
return JsonMaybeValue(self().m_checker, self().m_json, "", false);
}
2023-02-08 10:25:07 -05:00
JsonMaybeValue JsonMaybeObject::has(std::string const& key) {
2022-10-23 09:22:27 -04:00
this->addKnownKey(key);
2022-10-30 14:56:36 -04:00
if (this->isError()) return emptyValue();
2022-10-23 09:22:27 -04:00
if (!self().m_json.contains(key) || self().m_json[key].is_null()) {
return emptyValue();
}
2023-02-08 10:25:07 -05:00
return JsonMaybeValue(self().m_checker, self().m_json[key], key, true);
2022-10-23 09:22:27 -04:00
}
2023-02-08 10:25:07 -05:00
JsonMaybeValue JsonMaybeObject::needs(std::string const& key) {
2022-10-23 09:22:27 -04:00
this->addKnownKey(key);
2022-10-30 14:56:36 -04:00
if (this->isError()) return emptyValue();
2022-10-23 09:22:27 -04:00
if (!self().m_json.contains(key)) {
2022-10-30 14:56:36 -04:00
this->setError(self().m_hierarchy + " is missing required key \"" + key + "\"");
2022-10-23 09:22:27 -04:00
return emptyValue();
}
2023-02-08 10:25:07 -05:00
return JsonMaybeValue(self().m_checker, self().m_json[key], key, true);
2022-10-23 09:22:27 -04:00
}
2023-02-08 10:25:07 -05:00
// TODO: gross hack :3 (ctrl+f this comment to find the other part)
extern bool s_jsonCheckerShouldCheckUnknownKeys;
bool s_jsonCheckerShouldCheckUnknownKeys = true;
2023-02-08 10:25:07 -05:00
void JsonMaybeObject::checkUnknownKeys() {
if (!s_jsonCheckerShouldCheckUnknownKeys)
return;
for (auto& [key, _] : self().m_json.as_object()) {
2022-10-23 09:22:27 -04:00
if (!m_knownKeys.count(key)) {
log::warn("{} contains unknown key \"{}\"", self().m_hierarchy, key);
2022-10-23 09:22:27 -04:00
}
}
}
JsonChecker::JsonChecker(matjson::Value& json) : m_json(json), m_result(std::monostate()) {}
2023-02-08 10:25:07 -05:00
bool JsonChecker::isError() const {
2022-10-23 09:22:27 -04:00
return std::holds_alternative<std::string>(m_result);
}
2023-02-08 10:25:07 -05:00
std::string JsonChecker::getError() const {
2022-10-23 09:22:27 -04:00
return std::get<std::string>(m_result);
}
2023-02-08 10:25:07 -05:00
JsonMaybeValue JsonChecker::root(std::string const& hierarchy) {
2022-10-23 09:22:27 -04:00
return JsonMaybeValue(*this, m_json, hierarchy, true);
}