use super::DocComment;
use super::functions::Annotation;
use super::span::Span;
use super::type_path::TypePath;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum TypeAnnotation {
Basic(String),
Array(Box<TypeAnnotation>),
Tuple(Vec<TypeAnnotation>),
Object(Vec<ObjectTypeField>),
Function {
params: Vec<FunctionParam>,
returns: Box<TypeAnnotation>,
},
Union(Vec<TypeAnnotation>),
Intersection(Vec<TypeAnnotation>),
Generic {
name: TypePath,
args: Vec<TypeAnnotation>,
},
Reference(TypePath),
Void,
Never,
Null,
Undefined,
Dyn(Vec<TypePath>),
}
impl TypeAnnotation {
pub fn option(inner: TypeAnnotation) -> Self {
TypeAnnotation::Generic {
name: TypePath::simple("Option"),
args: vec![inner],
}
}
pub fn option_inner(&self) -> Option<&TypeAnnotation> {
match self {
TypeAnnotation::Generic { name, args }
if name.as_str() == "Option" && args.len() == 1 =>
{
args.first()
}
_ => None,
}
}
pub fn into_option_inner(self) -> Option<TypeAnnotation> {
match self {
TypeAnnotation::Generic { name, mut args }
if name.as_str() == "Option" && args.len() == 1 =>
{
Some(args.remove(0))
}
_ => None,
}
}
pub fn is_option(&self) -> bool {
self.option_inner().is_some()
}
pub fn as_simple_name(&self) -> Option<&str> {
match self {
TypeAnnotation::Reference(path) => Some(path.as_str()),
TypeAnnotation::Basic(name) => Some(name.as_str()),
_ => None,
}
}
pub fn as_type_name_str(&self) -> Option<&str> {
match self {
TypeAnnotation::Basic(name) => Some(name.as_str()),
TypeAnnotation::Reference(path) => Some(path.as_str()),
_ => None,
}
}
pub fn to_type_string(&self) -> String {
match self {
TypeAnnotation::Basic(name) => name.clone(),
TypeAnnotation::Reference(path) => path.to_string(),
TypeAnnotation::Array(inner) => format!("Array<{}>", inner.to_type_string()),
TypeAnnotation::Generic { name, args }
if name.as_str() == "Option" && args.len() == 1 =>
{
format!("{}?", args[0].to_type_string())
}
TypeAnnotation::Generic { name, args } => {
let args_str: Vec<String> = args.iter().map(|a| a.to_type_string()).collect();
format!("{}<{}>", name, args_str.join(", "))
}
TypeAnnotation::Tuple(items) => {
let items_str: Vec<String> = items.iter().map(|t| t.to_type_string()).collect();
format!("[{}]", items_str.join(", "))
}
TypeAnnotation::Union(items) => {
let items_str: Vec<String> = items.iter().map(|t| t.to_type_string()).collect();
items_str.join(" | ")
}
TypeAnnotation::Void => "void".to_string(),
TypeAnnotation::Never => "never".to_string(),
TypeAnnotation::Null => "null".to_string(),
TypeAnnotation::Undefined => "undefined".to_string(),
TypeAnnotation::Object(fields) => {
let fields_str: Vec<String> = fields
.iter()
.map(|f| {
let opt = if f.optional { "?" } else { "" };
let alias = f
.annotations
.iter()
.find(|a| a.name == "alias")
.and_then(|a| a.args.first())
.and_then(|arg| match arg {
super::expressions::Expr::Literal(
super::literals::Literal::String(s),
_,
) => Some(s.as_str()),
_ => None,
});
let alias_str = alias.map(|a| format!("@\"{}\" ", a)).unwrap_or_default();
format!(
"{}{}{}: {}",
alias_str,
f.name,
opt,
f.type_annotation.to_type_string()
)
})
.collect();
format!("{{{}}}", fields_str.join(", "))
}
_ => "any".to_string(),
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ObjectTypeField {
pub name: String,
pub optional: bool,
pub type_annotation: TypeAnnotation,
#[serde(default)]
pub annotations: Vec<Annotation>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct FunctionParam {
pub name: Option<String>,
pub optional: bool,
pub type_annotation: TypeAnnotation,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TypeParam {
pub name: String,
#[serde(default)]
pub span: Span,
#[serde(default)]
pub doc_comment: Option<DocComment>,
pub default_type: Option<TypeAnnotation>,
#[serde(default)]
pub trait_bounds: Vec<TypePath>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct WherePredicate {
pub type_name: String,
pub bounds: Vec<TypePath>,
}
impl PartialEq for TypeParam {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
&& self.doc_comment == other.doc_comment
&& self.default_type == other.default_type
&& self.trait_bounds == other.trait_bounds
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TypeAliasDef {
pub name: String,
#[serde(default)]
pub doc_comment: Option<DocComment>,
pub type_params: Option<Vec<TypeParam>>,
pub type_annotation: TypeAnnotation,
pub meta_param_overrides: Option<std::collections::HashMap<String, super::expressions::Expr>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InterfaceDef {
pub name: String,
#[serde(default)]
pub doc_comment: Option<DocComment>,
pub type_params: Option<Vec<TypeParam>>,
pub members: Vec<InterfaceMember>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum InterfaceMember {
Property {
name: String,
optional: bool,
type_annotation: TypeAnnotation,
#[serde(default)]
span: Span,
#[serde(default)]
doc_comment: Option<DocComment>,
},
Method {
name: String,
optional: bool,
params: Vec<FunctionParam>,
return_type: TypeAnnotation,
is_async: bool,
#[serde(default)]
span: Span,
#[serde(default)]
doc_comment: Option<DocComment>,
},
IndexSignature {
param_name: String,
param_type: String, return_type: TypeAnnotation,
#[serde(default)]
span: Span,
#[serde(default)]
doc_comment: Option<DocComment>,
},
}
impl InterfaceMember {
pub fn span(&self) -> Span {
match self {
InterfaceMember::Property { span, .. }
| InterfaceMember::Method { span, .. }
| InterfaceMember::IndexSignature { span, .. } => *span,
}
}
pub fn doc_comment(&self) -> Option<&DocComment> {
match self {
InterfaceMember::Property { doc_comment, .. }
| InterfaceMember::Method { doc_comment, .. }
| InterfaceMember::IndexSignature { doc_comment, .. } => doc_comment.as_ref(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EnumDef {
pub name: String,
#[serde(default)]
pub doc_comment: Option<DocComment>,
pub type_params: Option<Vec<TypeParam>>,
pub members: Vec<EnumMember>,
#[serde(default)]
pub annotations: Vec<super::Annotation>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EnumMember {
pub name: String,
pub kind: EnumMemberKind,
#[serde(default)]
pub span: Span,
#[serde(default)]
pub doc_comment: Option<DocComment>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum EnumMemberKind {
Unit { value: Option<EnumValue> },
Tuple(Vec<TypeAnnotation>),
Struct(Vec<ObjectTypeField>),
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum EnumValue {
String(String),
Number(f64),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum TraitMember {
Required(InterfaceMember),
Default(MethodDef),
AssociatedType {
name: String,
bounds: Vec<TypeAnnotation>,
#[serde(default)]
span: Span,
#[serde(default)]
doc_comment: Option<DocComment>,
},
}
impl TraitMember {
pub fn span(&self) -> Span {
match self {
TraitMember::Required(member) => member.span(),
TraitMember::Default(method) => method.span,
TraitMember::AssociatedType { span, .. } => *span,
}
}
pub fn doc_comment(&self) -> Option<&DocComment> {
match self {
TraitMember::Required(member) => member.doc_comment(),
TraitMember::Default(method) => method.doc_comment.as_ref(),
TraitMember::AssociatedType { doc_comment, .. } => doc_comment.as_ref(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AssociatedTypeBinding {
pub name: String,
pub concrete_type: TypeAnnotation,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TraitDef {
pub name: String,
#[serde(default)]
pub doc_comment: Option<DocComment>,
pub type_params: Option<Vec<TypeParam>>,
#[serde(default)]
pub super_traits: Vec<TypeAnnotation>,
pub members: Vec<TraitMember>,
#[serde(default)]
pub annotations: Vec<super::Annotation>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ImplBlock {
pub trait_name: TypeName,
pub target_type: TypeName,
pub impl_name: Option<String>,
pub methods: Vec<MethodDef>,
pub associated_type_bindings: Vec<AssociatedTypeBinding>,
pub where_clause: Option<Vec<WherePredicate>>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ExtendStatement {
pub type_name: TypeName,
pub methods: Vec<MethodDef>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MethodDef {
pub name: String,
#[serde(default)]
pub span: Span,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub declaring_module_path: Option<String>,
#[serde(default)]
pub doc_comment: Option<DocComment>,
#[serde(default)]
pub annotations: Vec<super::functions::Annotation>,
#[serde(default)]
pub type_params: Option<Vec<TypeParam>>,
pub params: Vec<super::functions::FunctionParameter>,
pub when_clause: Option<Box<super::expressions::Expr>>,
pub return_type: Option<TypeAnnotation>,
pub body: Vec<super::statements::Statement>,
pub is_async: bool,
}
impl PartialEq for MethodDef {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
&& self.doc_comment == other.doc_comment
&& self.annotations == other.annotations
&& self.type_params == other.type_params
&& self.params == other.params
&& self.when_clause == other.when_clause
&& self.return_type == other.return_type
&& self.body == other.body
&& self.is_async == other.is_async
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum TypeName {
Simple(TypePath),
Generic {
name: TypePath,
type_args: Vec<TypeAnnotation>,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StructTypeDef {
pub name: String,
#[serde(default)]
pub doc_comment: Option<DocComment>,
pub type_params: Option<Vec<TypeParam>>,
pub fields: Vec<StructField>,
#[serde(default)]
pub methods: Vec<MethodDef>,
pub annotations: Vec<Annotation>,
#[serde(default)]
pub native_layout: Option<NativeLayoutBinding>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct NativeLayoutBinding {
pub abi: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StructField {
pub annotations: Vec<Annotation>,
pub is_comptime: bool,
pub name: String,
#[serde(default)]
pub span: Span,
#[serde(default)]
pub doc_comment: Option<DocComment>,
pub type_annotation: TypeAnnotation,
pub default_value: Option<super::expressions::Expr>,
}
impl PartialEq for StructField {
fn eq(&self, other: &Self) -> bool {
self.annotations == other.annotations
&& self.is_comptime == other.is_comptime
&& self.name == other.name
&& self.doc_comment == other.doc_comment
&& self.type_annotation == other.type_annotation
&& self.default_value == other.default_value
}
}