feat(ast_tools): support #[estree(via)] on fieldless enum variants (#10746)

Generators for `ESTree` impls and TS type defs supports `#[estree(via = ...)]` on enum variants where the variant has a field. Extend this support to fieldless variants too.

```rs
#[ast]
#[generate_derive(ESTree)]
enum Foo<'a> {
    // This was already supported
    #[estree(via = FooBar)]
    Bar(Expression<'a>),
    // Add support for this
    #[estree(via = FooQux)]
    Qux,
}
```
This commit is contained in:
overlookmotel committed 2025-05-01 11:14:23 +00:00
1 parent ee79f03503
commit d0ba83c719
4 files changed
+39 -26

No files matched your search

@@ -35,7 +35,9 @@ impl ESTree for ImportImportName<'_> {
fn serialize<S: Serializer>(&self, serializer: S) {
match self {
Self::Name(it) => crate::serialize::ImportOrExportNameName(it).serialize(serializer),
Self::NamespaceObject => JsonSafeString("namespaceObject").serialize(serializer),
Self::NamespaceObject => {
crate::serialize::ImportImportNameNamespaceObject(()).serialize(serializer)
}
Self::Default(it) => {
crate::serialize::ImportOrExportNameDefault(it).serialize(serializer)
}
@@ -61,9 +63,11 @@ impl ESTree for ExportImportName<'_> {
fn serialize<S: Serializer>(&self, serializer: S) {
match self {
Self::Name(it) => crate::serialize::ImportOrExportNameName(it).serialize(serializer),
Self::All => JsonSafeString("all").serialize(serializer),
Self::AllButDefault => JsonSafeString("allButDefault").serialize(serializer),
Self::Null => JsonSafeString("null").serialize(serializer),
Self::All => crate::serialize::ExportImportNameAll(()).serialize(serializer),
Self::AllButDefault => {
crate::serialize::ExportImportNameAllButDefault(()).serialize(serializer)
}
Self::Null => crate::serialize::ExportNameNull(()).serialize(serializer),
}
}
}
@@ -75,7 +79,7 @@ impl ESTree for ExportExportName<'_> {
Self::Default(it) => {
crate::serialize::ImportOrExportNameDefault(it).serialize(serializer)
}
Self::Null => JsonSafeString("null").serialize(serializer),
Self::Null => crate::serialize::ExportNameNull(()).serialize(serializer),
}
}
}
@@ -85,7 +89,7 @@ impl ESTree for ExportLocalName<'_> {
match self {
Self::Name(it) => crate::serialize::ImportOrExportNameName(it).serialize(serializer),
Self::Default(it) => crate::serialize::ExportLocalNameDefault(it).serialize(serializer),
Self::Null => JsonSafeString("null").serialize(serializer),
Self::Null => crate::serialize::ExportNameNull(()).serialize(serializer),
}
}
}
+4 -4
View File
@@ -48,7 +48,7 @@ dummy_estree_impl!(ExportLocalNameDefault<'_, '_>);
/// Serializer for `Null` variant of `ExportLocalName`, `ExportExportName`, and `ExportImportName`.
#[ast_meta]
#[estree(ts_type = "Dummy", raw_deser = "{kind: 'None', name: null, start: null, end: null}")]
pub struct ExportNameNull;
pub struct ExportNameNull(pub ());
dummy_estree_impl!(ExportNameNull);
@@ -68,7 +68,7 @@ dummy_estree_impl!(ImportOrExportNameDefault<'_>);
/// Serializer for `All` variant of `ExportImportName`.
#[ast_meta]
#[estree(ts_type = "Dummy", raw_deser = "{kind: 'All', name: null, start: null, end: null}")]
pub struct ExportImportNameAll;
pub struct ExportImportNameAll(pub ());
dummy_estree_impl!(ExportImportNameAll);
@@ -78,7 +78,7 @@ dummy_estree_impl!(ExportImportNameAll);
ts_type = "Dummy",
raw_deser = "{kind: 'AllButDefault', name: null, start: null, end: null}"
)]
pub struct ExportImportNameAllButDefault;
pub struct ExportImportNameAllButDefault(pub ());
dummy_estree_impl!(ExportImportNameAllButDefault);
@@ -88,6 +88,6 @@ dummy_estree_impl!(ExportImportNameAllButDefault);
ts_type = "Dummy",
raw_deser = "{kind: 'NamespaceObject', name: null, start: null, end: null}"
)]
pub struct ImportImportNameNamespaceObject;
pub struct ImportImportNameNamespaceObject(pub ());
dummy_estree_impl!(ImportImportNameNamespaceObject);
+21 -10
View File
@@ -440,8 +440,7 @@ impl<'s> StructSerializerGenerator<'s> {
}
let value = if let Some(converter_name) = &field.estree.via {
let converter = self.schema.meta_by_name(converter_name);
let converter_path = converter.import_path_from_crate(self.krate, self.schema);
let converter_path = get_converter_path(converter_name, self.krate, self.schema);
quote!( #converter_path(#self_path) )
} else if let Some(append_field_index) = field.estree.append_field_index {
let append_field = &struct_def.fields[append_field_index];
@@ -511,17 +510,23 @@ fn generate_body_for_enum(enum_def: &EnumDef, schema: &Schema) -> TokenStream {
};
}
let converter_path = variant.estree.via.as_deref().map(|converter_name| {
get_converter_path(converter_name, enum_def.file(schema).krate(), schema)
});
if variant.is_fieldless() {
let value = get_fieldless_variant_value(enum_def, variant);
let value = string_to_tokens(value.as_ref(), false);
let value = if let Some(converter_path) = converter_path {
quote!( #converter_path(()) )
} else {
let value = get_fieldless_variant_value(enum_def, variant);
string_to_tokens(value.as_ref(), false)
};
quote! {
Self::#variant_ident => #value.serialize(serializer),
}
} else {
let value = if let Some(converter_name) = &variant.estree.via {
let converter = schema.meta_by_name(converter_name);
let krate = enum_def.file(schema).krate();
let converter_path = converter.import_path_from_crate(krate, schema);
let value = if let Some(converter_path) = converter_path {
quote!( #converter_path(it) )
} else {
quote!(it)
@@ -546,11 +551,17 @@ fn generate_body_for_via_override(
file: &File,
schema: &Schema,
) -> TokenStream {
let converter = schema.meta_by_name(converter_name);
let converter_path = converter.import_path_from_crate(file.krate(), schema);
let converter_path = get_converter_path(converter_name, file.krate(), schema);
quote!( #converter_path(self).serialize(serializer) )
}
/// Get path to converter from crate `from_krate`.
/// e.g. `oxc_ast::serialize::Null` or `crate::serialize::Null`.
fn get_converter_path(converter_name: &str, from_krate: &str, schema: &Schema) -> TokenStream {
let converter = schema.meta_by_name(converter_name);
converter.import_path_from_crate(from_krate, schema)
}
/// Get if a struct field should be skipped when serializing.
///
/// Returns `true` if either the field has an `#[estree(skip)]` attr on it,
+4 -6
View File
@@ -322,12 +322,10 @@ fn generate_ts_type_def_for_enum(enum_def: &EnumDef, schema: &Schema) -> Option<
.iter()
.filter(|variant| !should_skip_enum_variant(variant))
.map(|variant| {
if let Some(variant_type) = variant.field_type(schema) {
if let Some(converter_name) = &variant.estree.via {
Cow::Borrowed(get_ts_type_for_converter(converter_name, schema).unwrap())
} else {
ts_type_name(variant_type, schema)
}
if let Some(converter_name) = &variant.estree.via {
Cow::Borrowed(get_ts_type_for_converter(converter_name, schema).unwrap())
} else if let Some(variant_type) = variant.field_type(schema) {
ts_type_name(variant_type, schema)
} else {
format_cow!("'{}'", get_fieldless_variant_value(enum_def, variant))
}