Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions crates/oxc_ast/src/ast/js.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,9 +483,11 @@ pub use match_member_expression;
#[ast(visit)]
#[derive(Debug)]
#[generate_derive(CloneIn, GetSpan, GetSpanMut, ContentEq, ESTree)]
#[estree(rename = "MemberExpression", add_ts = "computed: true", add_entry(computed = true))]
pub struct ComputedMemberExpression<'a> {
pub span: Span,
pub object: Expression<'a>,
#[estree(rename = "property")]
pub expression: Expression<'a>,
pub optional: bool, // for optional chaining
}
Expand All @@ -496,6 +498,7 @@ pub struct ComputedMemberExpression<'a> {
#[ast(visit)]
#[derive(Debug)]
#[generate_derive(CloneIn, GetSpan, GetSpanMut, ContentEq, ESTree)]
#[estree(rename = "MemberExpression", add_ts = "computed: false", add_entry(computed = false))]
pub struct StaticMemberExpression<'a> {
pub span: Span,
pub object: Expression<'a>,
Expand All @@ -509,6 +512,7 @@ pub struct StaticMemberExpression<'a> {
#[ast(visit)]
#[derive(Debug)]
#[generate_derive(CloneIn, GetSpan, GetSpanMut, ContentEq, ESTree)]
#[estree(rename = "MemberExpression", add_ts = "computed: false", add_entry(computed = false))]
pub struct PrivateFieldExpression<'a> {
pub span: Span,
pub object: Expression<'a>,
Expand Down
11 changes: 7 additions & 4 deletions crates/oxc_ast/src/generated/derive_estree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -347,38 +347,41 @@ impl Serialize for MemberExpression<'_> {
impl Serialize for ComputedMemberExpression<'_> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("type", "ComputedMemberExpression")?;
map.serialize_entry("type", "MemberExpression")?;
map.serialize_entry("start", &self.span.start)?;
map.serialize_entry("end", &self.span.end)?;
map.serialize_entry("object", &self.object)?;
map.serialize_entry("expression", &self.expression)?;
map.serialize_entry("property", &self.expression)?;
map.serialize_entry("optional", &self.optional)?;
map.serialize_entry("computed", &true)?;
map.end()
}
}

impl Serialize for StaticMemberExpression<'_> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("type", "StaticMemberExpression")?;
map.serialize_entry("type", "MemberExpression")?;
map.serialize_entry("start", &self.span.start)?;
map.serialize_entry("end", &self.span.end)?;
map.serialize_entry("object", &self.object)?;
map.serialize_entry("property", &self.property)?;
map.serialize_entry("optional", &self.optional)?;
map.serialize_entry("computed", &false)?;
map.end()
}
}

impl Serialize for PrivateFieldExpression<'_> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut map = serializer.serialize_map(None)?;
map.serialize_entry("type", "PrivateFieldExpression")?;
map.serialize_entry("type", "MemberExpression")?;
map.serialize_entry("start", &self.span.start)?;
map.serialize_entry("end", &self.span.end)?;
map.serialize_entry("object", &self.object)?;
map.serialize_entry("field", &self.field)?;
map.serialize_entry("optional", &self.optional)?;
map.serialize_entry("computed", &false)?;
map.end()
}
}
Expand Down
54 changes: 54 additions & 0 deletions napi/parser/test/__snapshots__/parse.test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,59 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`parse > estree MemberExpression 1`] = `
[
{
"end": 15,
"expression": {
"computed": false,
"end": 14,
"object": {
"end": 3,
"name": "obj",
"start": 0,
"type": "Identifier",
},
"optional": false,
"property": {
"end": 14,
"name": "staticProp",
"start": 4,
"type": "Identifier",
},
"start": 0,
"type": "MemberExpression",
},
"start": 0,
"type": "ExpressionStatement",
},
{
"end": 36,
"expression": {
"computed": true,
"end": 35,
"object": {
"end": 19,
"name": "obj",
"start": 16,
"type": "Identifier",
},
"optional": false,
"property": {
"end": 34,
"raw": ""computedProp"",
"start": 20,
"type": "Literal",
"value": "computedProp",
},
"start": 16,
"type": "MemberExpression",
},
"start": 16,
"type": "ExpressionStatement",
},
]
`;

exports[`parse > estree function params 1`] = `
{
"async": true,
Expand Down
11 changes: 11 additions & 0 deletions napi/parser/test/parse.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,17 @@ describe('parse', () => {
);
expect(ret.program.body[0]).matchSnapshot();
});

it('estree MemberExpression', async () => {
const ret = await parseAsync(
'test.js',
`\
obj.staticProp;
obj["computedProp"];
`,
);
expect(ret.program.body).matchSnapshot();
});
});

describe('error', () => {
Expand Down
11 changes: 7 additions & 4 deletions npm/oxc-types/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,24 +174,27 @@ export interface TemplateElementValue {
export type MemberExpression = ComputedMemberExpression | StaticMemberExpression | PrivateFieldExpression;

export interface ComputedMemberExpression extends Span {
type: 'ComputedMemberExpression';
type: 'MemberExpression';
object: Expression;
expression: Expression;
property: Expression;
optional: boolean;
computed: true;
}

export interface StaticMemberExpression extends Span {
type: 'StaticMemberExpression';
type: 'MemberExpression';
object: Expression;
property: IdentifierName;
optional: boolean;
computed: false;
}

export interface PrivateFieldExpression extends Span {
type: 'PrivateFieldExpression';
type: 'MemberExpression';
object: Expression;
field: PrivateIdentifier;
optional: boolean;
computed: false;
}

export interface CallExpression extends Span {
Expand Down
23 changes: 23 additions & 0 deletions tasks/ast_tools/src/derives/estree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use quote::quote;
use syn::{parse_str, Type};

use crate::{
parse::attr::AttrPartListElement,
schema::{Def, EnumDef, FieldDef, Schema, StructDef, TypeDef, VariantDef},
utils::number_lit,
Result,
Expand Down Expand Up @@ -105,6 +106,19 @@ fn parse_estree_attr(location: AttrLocation, part: AttrPart) -> Result<()> {
AttrPart::Tag("no_type") => struct_def.estree.no_type = true,
AttrPart::Tag("custom_serialize") => struct_def.estree.custom_serialize = true,
AttrPart::Tag("no_ts_def") => struct_def.estree.custom_ts_def = Some(String::new()),
AttrPart::List("add_entry", args) => {
let args = args
.into_iter()
.map(|list_element| match list_element {
AttrPartListElement::String(name, value) => Ok((name, value)),
_ => Err(()),
})
.collect::<Result<Vec<_>>>()?;
if args.is_empty() {
return Err(());
}
struct_def.estree.add_entry = Some(args);
}
AttrPart::String("add_ts", value) => struct_def.estree.add_ts = Some(value),
AttrPart::String("custom_ts_def", value) => {
struct_def.estree.custom_ts_def = Some(value);
Expand Down Expand Up @@ -198,11 +212,20 @@ fn generate_body_for_struct(struct_def: &StructDef, schema: &Schema) -> TokenStr
quote!()
};

let add_entry = if let Some(add_entry) = &struct_def.estree.add_entry {
let (name, value) = &add_entry[0];
let value = parse_str::<syn::Expr>(value).unwrap();
quote!( map.serialize_entry(#name, &#value)?; )
} else {
quote!()
};

let stmts = gen.stmts;
quote! {
let mut map = serializer.serialize_map(None)?;
#type_field
#stmts
#add_entry
map.end()
}
}
Expand Down
1 change: 1 addition & 0 deletions tasks/ast_tools/src/schema/extensions/estree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub struct ESTreeStruct {
pub no_type: bool,
/// `true` if serializer is implemented manually and should not be generated
pub custom_serialize: bool,
pub add_entry: Option<Vec<(String, String)>>,
/// Additional fields to add to TS type definition
pub add_ts: Option<String>,
/// Custom TS type definition. Does not include `export`.
Expand Down