#pragma once #include #include #include #include #include "common/error.hpp" namespace smartbotic::config { class ConfigLoader { public: // Load configuration from file static common::Result loadFromFile(const std::filesystem::path& path); // Load configuration from string static common::Result loadFromString(const std::string& content); // Expand environment variables in JSON values (${VAR:default}) static nlohmann::json expandEnvVars(const nlohmann::json& config); // Get nested value with dot notation (e.g., "database.host") static std::optional get(const nlohmann::json& config, const std::string& path); // Get value with default template static T getOr(const nlohmann::json& config, const std::string& path, T defaultValue) { auto value = get(config, path); if (value.has_value()) { try { return value->get(); } catch (...) { return defaultValue; } } return defaultValue; } // Merge two configurations (second overrides first) static nlohmann::json merge(const nlohmann::json& base, const nlohmann::json& override); // Validate config against schema static common::Result validate(const nlohmann::json& config, const nlohmann::json& schema); }; // Configuration holder with typed accessors class Config { public: Config() = default; explicit Config(nlohmann::json data); // Load from file static common::Result fromFile(const std::filesystem::path& path); // Raw access const nlohmann::json& data() const { return data_; } nlohmann::json& data() { return data_; } // Get value with path template std::optional get(const std::string& path) const { auto value = ConfigLoader::get(data_, path); if (value.has_value()) { try { return value->get(); } catch (...) { return std::nullopt; } } return std::nullopt; } // Get value with default template T getOr(const std::string& path, T defaultValue) const { return ConfigLoader::getOr(data_, path, std::move(defaultValue)); } // Get required value (throws if not found) template T getRequired(const std::string& path) const { auto value = get(path); if (!value.has_value()) { throw common::SmartBoticException( common::Error(common::ErrorCode::InvalidArgument, "Required config value not found: " + path)); } return *value; } // Check if path exists bool has(const std::string& path) const; // Reload from file common::Result reload(const std::filesystem::path& path); private: nlohmann::json data_; }; } // namespace smartbotic::config