use syn::{Field, Type, TypePath};
#[expect(clippy::struct_excessive_bools)]
pub struct FieldAnalysis {
pub skip: bool,
pub required: bool,
pub has_default: bool,
pub nested: bool,
}
pub fn analyze_field(field: &Field) -> Result<FieldAnalysis, syn::Error> {
let mut analysis = FieldAnalysis {
skip: false,
required: false,
has_default: false,
nested: false,
};
for attr in &field.attrs {
if attr.path().is_ident("konfik") {
attr.parse_nested_meta(|meta| {
if meta.path.is_ident("skip") {
analysis.skip = true;
} else if meta.path.is_ident("nested") {
analysis.nested = true;
}
Ok(())
})?;
}
if attr.path().is_ident("command") {
attr.parse_nested_meta(|meta| {
if meta.path.is_ident("flatten") {
analysis.nested = true;
}
Ok(())
})?;
}
if attr.path().is_ident("serde") {
attr.parse_nested_meta(|meta| {
if meta.path.is_ident("skip") {
analysis.skip = true;
} else if meta.path.is_ident("default") {
analysis.has_default = true;
}
Ok(())
})?;
}
}
analysis.required = !is_option_type(&field.ty) && !analysis.has_default;
Ok(analysis)
}
fn is_option_type(ty: &Type) -> bool {
if let Type::Path(TypePath { path, .. }) = ty {
if let Some(segment) = path.segments.last() {
if segment.ident == "Option" {
return true;
}
}
}
false
}