use toml::Value;
#[derive(Debug)]
pub(crate) struct LakefileToml {
pub(crate) package_name: Option<String>,
pub(crate) lean_libs: Vec<String>,
}
pub(crate) fn parse_lakefile_toml(text: &str) -> Result<LakefileToml, toml::de::Error> {
let document: Value = toml::from_str(text)?;
let package_name = document
.get("name")
.and_then(Value::as_str)
.map(str::trim)
.filter(|name| !name.is_empty())
.map(str::to_owned);
let lean_libs = document
.get("lean_lib")
.and_then(Value::as_array)
.map(|entries| {
entries
.iter()
.filter_map(|entry| entry.as_table())
.filter_map(|table| table.get("name").and_then(Value::as_str))
.map(str::trim)
.filter(|name| !name.is_empty())
.map(str::to_owned)
.collect()
})
.unwrap_or_default();
Ok(LakefileToml {
package_name,
lean_libs,
})
}
#[cfg(test)]
#[allow(clippy::expect_used, clippy::panic)]
mod tests {
use super::parse_lakefile_toml;
#[test]
fn parses_package_name_and_lean_libs() {
let parsed = parse_lakefile_toml(
r#"
name = "demo"
defaultTargets = ["KanProofs"]
[[lean_lib]]
name = "KanProofs"
[[lean_lib]]
name = "Other"
"#,
)
.expect("valid TOML");
assert_eq!(parsed.package_name.as_deref(), Some("demo"));
assert_eq!(parsed.lean_libs, vec!["KanProofs", "Other"]);
}
#[test]
fn missing_name_yields_none() {
let parsed = parse_lakefile_toml("[[lean_lib]]\nname = \"Only\"\n").expect("valid TOML");
assert!(parsed.package_name.is_none());
assert_eq!(parsed.lean_libs, vec!["Only"]);
}
#[test]
fn empty_lean_lib_entries_are_skipped() {
let parsed = parse_lakefile_toml(
r#"
name = "demo"
[[lean_lib]]
name = ""
[[lean_lib]]
name = "Real"
"#,
)
.expect("valid TOML");
assert_eq!(parsed.lean_libs, vec!["Real"]);
}
#[test]
fn invalid_toml_errors() {
let err = parse_lakefile_toml("name = ").expect_err("invalid TOML");
let rendered = err.to_string();
assert!(!rendered.is_empty());
}
#[test]
fn lean_lib_without_name_is_skipped() {
let parsed = parse_lakefile_toml(
r#"
name = "demo"
[[lean_lib]]
defaultFacets = ["LeanLib.sharedFacet"]
"#,
)
.expect("valid TOML");
assert!(parsed.lean_libs.is_empty());
}
}