feat(ast_tools): Move tsify custom types to estree attribute macro (#6934)

Part of #6347
This commit is contained in:
ottomated 2024-10-28 01:45:27 +00:00
parent 169fa22350
commit fbc297ec7b
3 changed files with 28 additions and 40 deletions

View file

@ -294,7 +294,7 @@ pub struct ThisExpression {
pub struct ArrayExpression<'a> {
#[estree(flatten)]
pub span: Span,
#[tsify(type = "Array<SpreadElement | Expression | null>")]
#[estree(type = "Array<SpreadElement | Expression | null>")]
pub elements: Vec<'a, ArrayExpressionElement<'a>>,
/// Array trailing comma
/// <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Trailing_commas#arrays>
@ -832,7 +832,7 @@ pub use match_assignment_target_pattern;
pub struct ArrayAssignmentTarget<'a> {
#[estree(flatten)]
pub span: Span,
#[tsify(type = "Array<AssignmentTargetMaybeDefault | AssignmentTargetRest | null>")]
#[estree(type = "Array<AssignmentTargetMaybeDefault | AssignmentTargetRest | null>")]
pub elements: Vec<'a, Option<AssignmentTargetMaybeDefault<'a>>>,
#[estree(skip)]
pub rest: Option<AssignmentTargetRest<'a>>,
@ -850,7 +850,7 @@ pub struct ArrayAssignmentTarget<'a> {
pub struct ObjectAssignmentTarget<'a> {
#[estree(flatten)]
pub span: Span,
#[tsify(type = "Array<AssignmentTargetProperty | AssignmentTargetRest>")]
#[estree(type = "Array<AssignmentTargetProperty | AssignmentTargetRest>")]
pub properties: Vec<'a, AssignmentTargetProperty<'a>>,
#[estree(skip)]
pub rest: Option<AssignmentTargetRest<'a>>,
@ -1497,8 +1497,10 @@ pub struct DebuggerStatement {
#[estree(no_type)]
pub struct BindingPattern<'a> {
// serde(flatten) the attributes because estree has no `BindingPattern`
#[estree(flatten)]
#[tsify(type = "(BindingIdentifier | ObjectPattern | ArrayPattern | AssignmentPattern)")]
#[estree(
flatten,
type = "(BindingIdentifier | ObjectPattern | ArrayPattern | AssignmentPattern)"
)]
#[span]
pub kind: BindingPatternKind<'a>,
pub type_annotation: Option<Box<'a, TSTypeAnnotation<'a>>>,
@ -1540,7 +1542,7 @@ pub struct AssignmentPattern<'a> {
pub struct ObjectPattern<'a> {
#[estree(flatten)]
pub span: Span,
#[tsify(type = "Array<BindingProperty | BindingRestElement>")]
#[estree(type = "Array<BindingProperty | BindingRestElement>")]
pub properties: Vec<'a, BindingProperty<'a>>,
#[estree(skip)]
pub rest: Option<Box<'a, BindingRestElement<'a>>>,
@ -1566,7 +1568,7 @@ pub struct BindingProperty<'a> {
pub struct ArrayPattern<'a> {
#[estree(flatten)]
pub span: Span,
#[tsify(type = "Array<BindingPattern | BindingRestElement | null>")]
#[estree(type = "Array<BindingPattern | BindingRestElement | null>")]
pub elements: Vec<'a, Option<BindingPattern<'a>>>,
#[estree(skip)]
pub rest: Option<Box<'a, BindingRestElement<'a>>>,
@ -1713,7 +1715,7 @@ pub struct FormalParameters<'a> {
#[estree(flatten)]
pub span: Span,
pub kind: FormalParameterKind,
#[tsify(type = "Array<FormalParameter | FormalParameterRest>")]
#[estree(type = "Array<FormalParameter | FormalParameterRest>")]
pub items: Vec<'a, FormalParameter<'a>>,
#[estree(skip)]
pub rest: Option<Box<'a, BindingRestElement<'a>>>,

View file

@ -73,7 +73,7 @@ fn typescript_struct(def: &StructDef) -> String {
if field.markers.derive_attributes.estree.skip {
continue;
}
let ty = match &field.markers.derive_attributes.tsify_type {
let ty = match &field.markers.derive_attributes.estree.typescript_type {
Some(ty) => ty.clone(),
None => type_to_string(field.typ.name()),
};

View file

@ -74,7 +74,6 @@ pub struct ScopeMarkers {
pub struct DeriveAttributes {
pub clone_in: CloneInAttribute,
pub estree: ESTreeFieldAttribute,
pub tsify_type: Option<String>,
}
/// A enum representing the value passed in `#[clone_in(...)]` derive helper attribute.
@ -169,6 +168,7 @@ pub struct ESTreeFieldAttribute {
pub flatten: bool,
pub skip: bool,
pub rename: Option<String>,
pub typescript_type: Option<String>,
}
impl Parse for ESTreeFieldAttribute {
@ -176,9 +176,16 @@ impl Parse for ESTreeFieldAttribute {
let mut flatten = false;
let mut skip = false;
let mut rename = None;
let mut typescript_type = None;
loop {
let ident = input.call(Ident::parse_any).unwrap().to_string();
let is_type = input.peek(Token![type]);
let ident = if is_type {
input.parse::<Token![type]>()?;
"type".to_string()
} else {
input.call(Ident::parse_any).unwrap().to_string()
};
match ident.as_str() {
"rename" => {
input.parse::<Token![=]>()?;
@ -201,6 +208,13 @@ impl Parse for ESTreeFieldAttribute {
skip = true;
}
}
"type" => {
input.parse::<Token![=]>()?;
assert!(
typescript_type.replace(input.parse::<LitStr>()?.value()).is_none(),
"Duplicate estree(type)"
);
}
arg => panic!("Unsupported #[estree(...)] argument: {arg}"),
}
let comma = input.peek(Token![,]);
@ -210,19 +224,7 @@ impl Parse for ESTreeFieldAttribute {
break;
}
}
Ok(Self { flatten, skip, rename })
}
}
/// A struct representing the `#[tsify(type = "...")]` attribute.
pub struct TsifyAttribute(String);
impl Parse for TsifyAttribute {
fn parse(input: ParseStream) -> Result<Self, syn::Error> {
input.parse::<Token![type]>()?;
input.parse::<Token![=]>()?;
let type_ = input.parse::<LitStr>()?;
Ok(Self(type_.value()))
Ok(Self { flatten, skip, rename, typescript_type })
}
}
@ -364,17 +366,8 @@ where
Ok(None)
}
}
fn try_parse_tsify_type(attr: &Attribute) -> crate::Result<Option<String>> {
if attr.path().is_ident("tsify") {
let arg = attr.parse_args_with(TsifyAttribute::parse).normalize()?;
Ok(Some(arg.0))
} else {
Ok(None)
}
}
let mut clone_in = None;
let mut estree = None;
let mut tsify_type = None;
for attr in attrs {
if let Some(attr) = try_parse_clone_in(attr)? {
assert!(clone_in.replace(attr).is_none(), "Duplicate `#[clone_in(...)]` attribute.");
@ -382,17 +375,10 @@ where
if let Some(attr) = try_parse_estree(attr)? {
assert!(estree.replace(attr).is_none(), "Duplicate `#[estree(...)]` attribute.");
}
if let Some(attr) = try_parse_tsify_type(attr)? {
assert!(
tsify_type.replace(attr).is_none(),
"Duplicate `#[tsify(type = \"...\")]` attribute."
);
}
}
Ok(DeriveAttributes {
clone_in: clone_in.unwrap_or_default(),
estree: estree.unwrap_or_default(),
tsify_type,
})
}