use serde_yaml_ng::Value;
#[derive(Debug, Clone, PartialEq)]
pub struct UnknownField {
pub path: String,
pub data_type: UnknownFieldType,
pub example: String,
}
#[derive(Debug, Clone, PartialEq)]
pub enum UnknownFieldType {
String,
Number,
Boolean,
Null,
Object,
Array,
}
pub fn value_to_type(value: &Value) -> UnknownFieldType {
match value {
Value::String(_) => UnknownFieldType::String,
Value::Number(_) => UnknownFieldType::Number,
Value::Bool(_) => UnknownFieldType::Boolean,
Value::Null => UnknownFieldType::Null,
Value::Mapping(_) => UnknownFieldType::Object,
Value::Sequence(_) => UnknownFieldType::Array,
Value::Tagged(tagged) => value_to_type(&tagged.value),
}
}
pub fn value_to_example(value: &Value) -> String {
match value {
Value::String(s) => {
if s.len() > 100 {
format!("{}...", &s[..100])
} else {
s.clone()
}
}
Value::Number(n) => n.to_string(),
Value::Bool(b) => b.to_string(),
Value::Null => "null".to_string(),
Value::Mapping(_) => "{...}".to_string(),
Value::Sequence(seq) => format!("[{} items]", seq.len()),
Value::Tagged(tagged) => {
format!("!{} {}", tagged.tag, value_to_example(&tagged.value))
}
}
}
pub fn collect_leaf_fields(base_path: &str, value: &Value) -> Vec<UnknownField> {
let mut fields = Vec::new();
match value {
Value::String(_) | Value::Number(_) | Value::Bool(_) | Value::Null => {
fields.push(UnknownField {
path: base_path.to_string(),
data_type: value_to_type(value),
example: value_to_example(value),
});
}
Value::Mapping(map) => {
for (key, val) in map {
if let Some(key_str) = key.as_str() {
let child_path = if base_path.is_empty() {
key_str.to_string()
} else {
format!("{}.{}", base_path, key_str)
};
fields.extend(collect_leaf_fields(&child_path, val));
}
}
}
Value::Sequence(seq) => {
for (i, val) in seq.iter().enumerate() {
let child_path = format!("{}[{}]", base_path, i);
fields.extend(collect_leaf_fields(&child_path, val));
}
}
Value::Tagged(tagged) => {
fields.extend(collect_leaf_fields(base_path, &tagged.value));
}
}
fields
}