use saphyr::{LoadableYamlNode, Yaml};
use super::collect::{Value, collect};
pub(crate) fn extract(text: &str) -> Vec<String> {
let Ok(documents) = Yaml::load_from_str(text) else {
return Vec::new();
};
collect(&Value::Seq(documents.iter().map(convert).collect()))
}
fn convert(value: &Yaml<'_>) -> Value {
match value {
Yaml::Value(scalar) => scalar
.as_str()
.map_or(Value::Other, |text| Value::Str(text.to_string())),
Yaml::Sequence(items) => Value::Seq(items.iter().map(convert).collect()),
Yaml::Mapping(entries) => Value::Map(entries.values().map(convert).collect()),
_ => Value::Other,
}
}
pub(crate) fn parse_error(text: &str) -> Option<String> {
Yaml::load_from_str(text)
.err()
.map(|error| format!("Invalid YAML: {error}"))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn plain_quoted_and_single_quoted_scalars_are_all_values() {
let document = "a: Unquoted plain\nb: \"Double quoted\"\nc: 'Single quoted'";
assert_eq!(
extract(document),
["Unquoted plain", "Double quoted", "Single quoted"]
);
}
#[test]
fn keys_are_never_extracted() {
assert_eq!(extract("title: value"), ["value"]);
}
#[test]
fn typed_scalars_are_dropped() {
assert_eq!(extract("n: 42\nb: true\nz: null\ns: kept"), ["kept"]);
}
#[test]
fn sequences_and_inline_maps_are_followed() {
let document = "list:\n - plain\n - \"quoted\"\ninline: { k: \"in\", p: bare }";
assert_eq!(extract(document), ["plain", "quoted", "in", "bare"]);
}
#[test]
fn a_block_scalar_is_one_value() {
assert_eq!(extract("b: |\n first\n second\n"), ["first\nsecond"]);
}
#[test]
fn a_folded_scalar_is_joined() {
assert_eq!(extract("f: >\n folded text\n"), ["folded text"]);
}
#[test]
fn every_document_in_the_file_is_read() {
assert_eq!(extract("a: first\n---\nb: second\n"), ["first", "second"]);
}
#[test]
fn yes_and_no_are_strings_not_booleans() {
assert_eq!(
extract("a: yes\nb: no\nc: on\nd: off"),
["yes", "no", "on", "off"]
);
}
#[test]
fn a_broken_document_yields_nothing_and_says_why() {
assert!(extract("a: [unterminated").is_empty());
assert!(parse_error("a: [unterminated").is_some());
assert!(parse_error("a: b").is_none());
}
}