use indexmap::IndexMap;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct LinkML {
pub id: String,
pub name: String,
pub title: String,
#[serde(
default,
skip_serializing_if = "Option::is_none",
deserialize_with = "remove_newlines"
)]
pub description: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub license: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub see_also: Vec<String>,
#[serde(skip_serializing_if = "IndexMap::is_empty")]
pub prefixes: IndexMap<String, String>,
pub default_prefix: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub default_range: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub imports: Vec<String>,
#[serde(default, skip_serializing_if = "IndexMap::is_empty")]
pub classes: IndexMap<String, ClassDefinition>,
#[serde(default, skip_serializing_if = "IndexMap::is_empty")]
pub slots: IndexMap<String, AttributeDefinition>,
#[serde(default, skip_serializing_if = "IndexMap::is_empty")]
pub enums: IndexMap<String, EnumDefinition>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Contributor {
pub name: String,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Subset {
#[serde(
default,
skip_serializing_if = "Option::is_none",
deserialize_with = "remove_newlines"
)]
pub description: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct TypeDefinition {
pub base: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub pattern: Option<String>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
deserialize_with = "remove_newlines"
)]
pub description: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub minimum_value: Option<i64>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct EnumDefinition {
#[serde(
default,
skip_serializing_if = "is_empty_string_option",
deserialize_with = "remove_newlines"
)]
pub description: Option<String>,
#[serde(skip_serializing_if = "IndexMap::is_empty")]
pub permissible_values: IndexMap<String, PermissibleValue>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct PermissibleValue {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub text: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub meaning: Option<String>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
deserialize_with = "remove_newlines"
)]
pub description: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct ClassDefinition {
#[serde(
default,
skip_serializing_if = "is_empty_string_option",
deserialize_with = "remove_newlines"
)]
pub description: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub class_uri: Option<String>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub slots: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub is_a: Option<String>,
#[serde(default, skip_serializing_if = "is_false_option")]
pub tree_root: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub slot_usage: Option<IndexMap<String, SlotUsage>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub attributes: Option<IndexMap<String, AttributeDefinition>>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub mixins: Vec<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Annotation {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub value: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct SlotUsage {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub pattern: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct AttributeDefinition {
#[serde(
default,
skip_serializing_if = "is_empty_string_option",
deserialize_with = "remove_newlines"
)]
pub description: Option<String>,
#[serde(default, skip_serializing_if = "is_empty_string_option")]
pub slot_uri: Option<String>,
#[serde(default, skip_serializing_if = "is_false_option")]
pub identifier: Option<bool>,
#[serde(default, skip_serializing_if = "is_false_option")]
pub required: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub range: Option<String>,
#[serde(default, skip_serializing_if = "is_false_option")]
pub readonly: Option<bool>,
#[serde(default, skip_serializing_if = "is_false_option")]
pub multivalued: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub minimum_value: Option<i64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub maximum_value: Option<i64>,
#[serde(default, skip_serializing_if = "is_false_option")]
pub recommended: Option<bool>,
#[serde(default, skip_serializing_if = "Vec::is_empty")]
pub examples: Vec<Example>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub annotations: Option<IndexMap<String, Annotation>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct Example {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub value: Option<String>,
#[serde(
default,
skip_serializing_if = "is_empty_string_option",
deserialize_with = "remove_newlines"
)]
pub description: Option<String>,
}
fn remove_newlines<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
where
D: serde::Deserializer<'de>,
{
let opt = Option::<String>::deserialize(deserializer)?;
Ok(opt.map(|s| {
s.lines()
.map(|line| line.trim())
.collect::<Vec<&str>>()
.join(" ")
}))
}
fn is_empty_string_option(s: &Option<String>) -> bool {
s.is_none() || s.as_ref().unwrap().is_empty()
}
fn is_false_option(s: &Option<bool>) -> bool {
s.is_none() || !s.as_ref().unwrap()
}