use serde::Deserialize;
pub const MANIFEST_FILE: &str = "autumn-starter.toml";
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
pub struct Manifest {
pub starter: StarterMeta,
}
#[derive(Debug, Clone, Deserialize, PartialEq, Eq)]
pub struct StarterMeta {
pub name: String,
pub description: String,
#[serde(default)]
pub verbatim: Vec<String>,
#[serde(default)]
pub post_scaffold_notes: Option<String>,
}
impl Manifest {
pub fn parse(toml_src: &str) -> Result<Self, String> {
toml::from_str(toml_src).map_err(|e| e.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parses_full_manifest() {
let src = r#"
[starter]
name = "saas"
description = "Multi-tenant SaaS starter"
verbatim = ["static/js/htmx.min.js"]
post_scaffold_notes = "cd {{project_name}} && autumn dev"
"#;
let m = Manifest::parse(src).unwrap();
assert_eq!(m.starter.name, "saas");
assert_eq!(m.starter.description, "Multi-tenant SaaS starter");
assert_eq!(m.starter.verbatim, vec!["static/js/htmx.min.js".to_owned()]);
assert_eq!(
m.starter.post_scaffold_notes.as_deref(),
Some("cd {{project_name}} && autumn dev")
);
}
#[test]
fn parses_minimal_manifest_with_defaults() {
let src = r#"
[starter]
name = "minimal"
description = "A tiny starter"
"#;
let m = Manifest::parse(src).unwrap();
assert_eq!(m.starter.name, "minimal");
assert!(m.starter.verbatim.is_empty());
assert!(m.starter.post_scaffold_notes.is_none());
}
#[test]
fn rejects_manifest_missing_required_fields() {
let src = r#"
[starter]
name = "broken"
"#;
assert!(Manifest::parse(src).is_err());
}
}