pub fn string_valued_entries(
entries: &serde_json::Map<String, serde_json::Value>,
) -> impl Iterator<Item = (&str, &str)> {
entries
.iter()
.filter_map(|(name, value)| Some((name.as_str(), value.as_str()?)))
}
pub fn deserialize_string_or_string_array<'de, D>(
deserializer: D,
) -> std::result::Result<Option<Vec<String>>, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::Deserialize;
let value = serde_json::Value::deserialize(deserializer)?;
Ok(match value {
serde_json::Value::String(s) => Some(vec![s]),
serde_json::Value::Array(entries) => {
let had_entries = !entries.is_empty();
let strings: Vec<String> = entries
.into_iter()
.filter_map(|entry| match entry {
serde_json::Value::String(s) => Some(s),
_ => None,
})
.collect();
if had_entries && strings.is_empty() {
None
} else {
Some(strings)
}
}
_ => None,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_string_valued_entries_skips_every_non_string_value_kind() {
let deps = serde_json::json!({
"bad-object": {"nested": "0.0.1"},
"bad-number": 1,
"bad-bool": true,
"bad-null": null,
"bad-array": ["1.0.0"],
"express": "^4.18.2",
});
let deps = deps.as_object().unwrap();
let mut entries: Vec<_> = string_valued_entries(deps).collect();
entries.sort_unstable();
assert_eq!(entries, vec![("express", "^4.18.2")]);
}
#[test]
fn test_string_valued_entries_all_invalid_yields_empty() {
let deps = serde_json::json!({
"bad-object": {"nested": "0.0.1"},
"bad-number": 1,
});
let deps = deps.as_object().unwrap();
assert_eq!(string_valued_entries(deps).count(), 0);
}
#[test]
fn test_string_valued_entries_empty_object_yields_empty() {
let deps = serde_json::json!({});
let deps = deps.as_object().unwrap();
assert_eq!(string_valued_entries(deps).count(), 0);
}
#[test]
fn test_deserialize_string_or_string_array_bare_string() {
assert_eq!(
deserialize_string_or_string_array(serde_json::json!("MIT")).unwrap(),
Some(vec!["MIT".to_string()])
);
}
#[test]
fn test_deserialize_string_or_string_array_of_strings() {
assert_eq!(
deserialize_string_or_string_array(serde_json::json!(["MIT", "Apache-2.0"])).unwrap(),
Some(vec!["MIT".to_string(), "Apache-2.0".to_string()])
);
}
#[test]
fn test_deserialize_string_or_string_array_empty_array() {
assert_eq!(
deserialize_string_or_string_array(serde_json::json!([])).unwrap(),
Some(vec![])
);
}
#[test]
fn test_deserialize_string_or_string_array_mixed_array_keeps_only_strings() {
assert_eq!(
deserialize_string_or_string_array(serde_json::json!(["MIT", 7, "Apache-2.0"]))
.unwrap(),
Some(vec!["MIT".to_string(), "Apache-2.0".to_string()])
);
}
#[test]
fn test_deserialize_string_or_string_array_all_non_string_array_is_none() {
assert_eq!(
deserialize_string_or_string_array(serde_json::json!([7, 8])).unwrap(),
None
);
}
#[test]
fn test_deserialize_string_or_string_array_other_shapes_are_none() {
for value in [
serde_json::json!(42),
serde_json::json!(true),
serde_json::json!({"not": "a list"}),
serde_json::json!(null),
] {
assert_eq!(deserialize_string_or_string_array(value).unwrap(), None);
}
}
}