#pragma once #include #include #include #include #include namespace faset::authoring { class SchemaRegistry { public: void register_schema(const Json& schema); void register_schemas(const Json& schemas); bool contains(const std::string& type) const; Json schema(const std::string& type) const; Json manifest() const; Json default_fields(const std::string& type) const; // Unknown fields and absent schemas survive authoring. Known fields are validated. void validate_component(const Json& component) const; Json migrate_component(const Json& component) const; void add_migration(const std::string& type, int from_version, Json field_rules); private: std::map schemas_; std::map,Json> migrations_; }; template class TypeRegistration { public: TypeRegistration(SchemaRegistry& registry, std::string id, std::string name, int version=1) : registry_(registry),schema_{{"id",std::move(id)},{"name",std::move(name)},{"version",version},{"fields",Json::object()}} {} template TypeRegistration& field(std::string id, std::string name, Value T::*member, Value default_value, std::string kind, Json constraints=Json::object()) { static_assert(std::is_member_object_pointer_v); require(!schema_["fields"].contains(id),"schema.duplicate_field","Duplicate stable FieldId"); // Converting the typed default checks supported JSON serialization at compile time. Json descriptor={{"id",id},{"name",std::move(name)},{"type",std::move(kind)},{"default",Json(default_value)}}; descriptor.update(constraints); schema_["fields"][id]=std::move(descriptor); return *this; } void commit() { registry_.register_schema(schema_); } private: SchemaRegistry& registry_; Json schema_; }; SchemaRegistry builtin_schemas(); void validate_field(const Json& value,const Json& descriptor); }