use crate::selector::{Selector, SelectorSegment};
pub fn yaml_to_json(value: &serde_yaml::Value) -> serde_json::Value {
match value {
serde_yaml::Value::Null => serde_json::Value::Null,
serde_yaml::Value::Bool(boolean) => serde_json::Value::Bool(*boolean),
serde_yaml::Value::Number(number) => {
if let Some(integer) = number.as_i64() {
serde_json::Value::Number(integer.into())
} else if let Some(float) = number.as_f64() {
serde_json::json!(float)
} else {
serde_json::Value::String(number.to_string())
}
}
serde_yaml::Value::String(string) => serde_json::Value::String(string.clone()),
serde_yaml::Value::Sequence(sequence) => serde_json::Value::Array(sequence.iter().map(yaml_to_json).collect()),
serde_yaml::Value::Mapping(mapping) => {
let mut map = serde_json::Map::new();
for (key, yaml_value) in mapping {
let json_key = match key {
serde_yaml::Value::String(string) => string.clone(),
_ => format!("{:?}", key),
};
map.insert(json_key, yaml_to_json(yaml_value));
}
serde_json::Value::Object(map)
}
serde_yaml::Value::Tagged(tagged) => yaml_to_json(&tagged.value),
}
}
pub fn resolve_select_field(value: &serde_yaml::Value, field: &str) -> serde_json::Value {
let parsed = Selector::parse(field);
let segments = parsed.segments();
if segments.len() == 1 {
if let SelectorSegment::Key(key) = &segments[0] {
if let serde_yaml::Value::Mapping(map) = value {
for (map_key, yaml_value) in map {
if let serde_yaml::Value::String(key_string) = map_key {
if key_string == key {
return yaml_to_json(yaml_value);
}
}
}
}
return serde_json::Value::Null;
}
}
let mut current_values = vec![value.clone()];
for segment in segments {
let mut next_values = Vec::new();
for current in ¤t_values {
match segment {
SelectorSegment::AllItems => {
if let serde_yaml::Value::Sequence(sequence) = current {
next_values.extend(sequence.iter().cloned());
}
}
SelectorSegment::Index(index) => {
if let serde_yaml::Value::Sequence(sequence) = current {
if let Some(item) = sequence.get(*index) {
next_values.push(item.clone());
}
}
}
SelectorSegment::Key(key) => {
if let serde_yaml::Value::Mapping(map) = current {
for (map_key, yaml_value) in map {
if let serde_yaml::Value::String(key_string) = map_key {
if key_string == key {
next_values.push(yaml_value.clone());
}
}
}
}
}
}
}
current_values = next_values;
}
let used_all_items = parsed.segments().iter().any(|s| matches!(s, SelectorSegment::AllItems));
if current_values.is_empty() {
if used_all_items {
serde_json::Value::Array(Vec::new())
} else {
serde_json::Value::Null
}
} else if current_values.len() == 1 && !used_all_items {
yaml_to_json(¤t_values[0])
} else {
serde_json::Value::Array(current_values.iter().map(yaml_to_json).collect())
}
}
pub fn select_field_key(field: &str) -> String {
let parsed = Selector::parse(field);
parsed
.segments()
.iter()
.find_map(|segment| {
if let SelectorSegment::Key(key) = segment {
Some(key.clone())
} else {
None
}
})
.unwrap_or_else(|| field.to_string())
}