use crate::model::{
Attribute, Deprecation, Docstring, ExceptionEntry, FreeSectionKind, Method, Parameter, Reference, Return, Section,
SeeAlsoEntry,
};
use crate::parse::numpy::kind::NumPySectionKind;
use crate::parse::numpy::nodes::{NumPyDocstring, NumPySection};
use crate::parse::utils::convert_multiline_with_indentation;
use crate::syntax::Parsed;
pub fn to_model(parsed: &Parsed) -> Option<Docstring> {
let source = parsed.source();
let root = NumPyDocstring::cast(parsed.root())?;
let summary = root.summary().map(|t| t.text(source).to_owned());
let extended_summary = root.extended_summary().map(|t| t.text(source).to_owned());
let deprecation = root.deprecation().map(|dep| Deprecation {
version: dep.version().text(source).to_owned(),
description: dep.description().map(|t| t.text(source).to_owned()),
});
let sections = root.sections().map(|s| convert_section(&s, source)).collect();
Some(Docstring {
summary,
extended_summary,
deprecation,
sections,
})
}
fn convert_section(section: &NumPySection<'_>, source: &str) -> Section {
let kind = section.section_kind(source);
match kind {
NumPySectionKind::Parameters | NumPySectionKind::Receives => {
let entries = section.parameters().map(|p| convert_parameter(&p, source)).collect();
match kind {
NumPySectionKind::Parameters => Section::Parameters(entries),
NumPySectionKind::Receives => Section::Receives(entries),
_ => unreachable!(),
}
}
NumPySectionKind::OtherParameters => {
Section::OtherParameters(section.parameters().map(|p| convert_parameter(&p, source)).collect())
}
NumPySectionKind::Returns => {
let entries: Vec<Return> = section
.returns()
.map(|r| Return {
name: r.name().map(|t| t.text(source).to_owned()),
type_annotation: r.return_type().map(|t| t.text(source).to_owned()),
description: r
.description()
.map(|t| convert_multiline_with_indentation(t.text(source))),
})
.collect();
Section::Returns(entries)
}
NumPySectionKind::Yields => {
let entries: Vec<Return> = section
.yields()
.map(|r| Return {
name: r.name().map(|t| t.text(source).to_owned()),
type_annotation: r.return_type().map(|t| t.text(source).to_owned()),
description: r
.description()
.map(|t| convert_multiline_with_indentation(t.text(source))),
})
.collect();
Section::Yields(entries)
}
NumPySectionKind::Raises => Section::Raises(
section
.exceptions()
.map(|e| ExceptionEntry {
type_name: e.r#type().text(source).to_owned(),
description: e
.description()
.map(|t| convert_multiline_with_indentation(t.text(source))),
})
.collect(),
),
NumPySectionKind::Warns => Section::Warns(
section
.warnings()
.map(|w| ExceptionEntry {
type_name: w.r#type().text(source).to_owned(),
description: w
.description()
.map(|t| convert_multiline_with_indentation(t.text(source))),
})
.collect(),
),
NumPySectionKind::SeeAlso => Section::SeeAlso(
section
.see_also_items()
.map(|item| SeeAlsoEntry {
names: item.names().map(|n| n.text(source).to_owned()).collect(),
description: item
.description()
.map(|t| convert_multiline_with_indentation(t.text(source))),
})
.collect(),
),
NumPySectionKind::References => Section::References(
section
.references()
.map(|r| Reference {
number: r.number().map(|t| t.text(source).to_owned()),
content: r.content().map(|t| convert_multiline_with_indentation(t.text(source))),
})
.collect(),
),
NumPySectionKind::Attributes => Section::Attributes(
section
.attributes()
.map(|a| Attribute {
name: a.name().text(source).to_owned(),
type_annotation: a.r#type().map(|t| t.text(source).to_owned()),
description: a
.description()
.map(|t| convert_multiline_with_indentation(t.text(source))),
})
.collect(),
),
NumPySectionKind::Methods => Section::Methods(
section
.methods()
.map(|m| Method {
name: m.name().text(source).to_owned(),
type_annotation: None,
description: m
.description()
.map(|t| convert_multiline_with_indentation(t.text(source))),
})
.collect(),
),
_ => {
let body = section
.body_text()
.map(|t| t.text(source).to_owned())
.unwrap_or_default();
let free_kind = match kind {
NumPySectionKind::Notes => FreeSectionKind::Notes,
NumPySectionKind::Examples => FreeSectionKind::Examples,
NumPySectionKind::Warnings => FreeSectionKind::Warnings,
NumPySectionKind::Unknown => FreeSectionKind::Unknown(section.header().name().text(source).to_owned()),
_ => unreachable!(),
};
Section::FreeText { kind: free_kind, body }
}
}
}
fn convert_parameter(param: &crate::parse::numpy::nodes::NumPyParameter<'_>, source: &str) -> Parameter {
Parameter {
names: param.names().map(|n| n.text(source).to_owned()).collect(),
type_annotation: param.r#type().map(|t| t.text(source).to_owned()),
description: param
.description()
.map(|t| convert_multiline_with_indentation(t.text(source))),
is_optional: param.optional().is_some(),
default_value: param.default_value().map(|t| t.text(source).to_owned()),
}
}