use serde_yaml::{Mapping, Value};
pub const PLATFORM_OWNED_SKILL_KEYS: [&str; 7] = [
"name",
"title",
"description",
"tags",
"category",
"display_category",
"hosts",
];
pub fn is_platform_owned_skill_key(key: &Value) -> bool {
key.as_str()
.is_some_and(|key| PLATFORM_OWNED_SKILL_KEYS.contains(&key))
}
pub fn render_passthrough_frontmatter(
frontmatter: Option<&Mapping>,
) -> Result<String, serde_yaml::Error> {
let Some(frontmatter) = frontmatter else {
return Ok(String::new());
};
let kept: Mapping = frontmatter
.iter()
.filter(|(key, _)| !is_platform_owned_skill_key(key))
.map(|(key, value)| (key.clone(), value.clone()))
.collect();
if kept.is_empty() {
return Ok(String::new());
}
serde_yaml::to_string(&sorted_mapping(&kept))
}
fn sorted_mapping(mapping: &Mapping) -> Mapping {
let mut entries: Vec<(&Value, &Value)> = mapping.iter().collect();
entries.sort_by_key(|(key, _)| sort_key(key));
entries
.into_iter()
.map(|(key, value)| (key.clone(), sorted_value(value)))
.collect()
}
fn sorted_value(value: &Value) -> Value {
match value {
Value::Mapping(mapping) => Value::Mapping(sorted_mapping(mapping)),
Value::Sequence(items) => Value::Sequence(items.iter().map(sorted_value).collect()),
Value::Tagged(tagged) => Value::Tagged(Box::new(serde_yaml::value::TaggedValue {
tag: tagged.tag.clone(),
value: sorted_value(&tagged.value),
})),
other => other.clone(),
}
}
fn sort_key(key: &Value) -> String {
key.as_str().map_or_else(
|| serde_yaml::to_string(key).unwrap_or_default(),
str::to_owned,
)
}