diff --git a/crates/oxc_ast/src/ast/jsx.rs b/crates/oxc_ast/src/ast/jsx.rs index d41e78c23..96eac3f4c 100644 --- a/crates/oxc_ast/src/ast/jsx.rs +++ b/crates/oxc_ast/src/ast/jsx.rs @@ -83,7 +83,7 @@ pub struct JSXClosingFragment { #[cfg_attr(feature = "serialize", serde(untagged))] pub enum JSXElementName<'a> { /// `` - Identifier(JSXIdentifier<'a>), + Identifier(Box<'a, JSXIdentifier<'a>>), /// `` NamespacedName(Box<'a, JSXNamespacedName<'a>>), /// `` @@ -131,7 +131,7 @@ impl<'a> JSXMemberExpression<'a> { #[cfg_attr(feature = "serialize", derive(Serialize, Tsify))] #[cfg_attr(feature = "serialize", serde(untagged))] pub enum JSXMemberExpressionObject<'a> { - Identifier(JSXIdentifier<'a>), + Identifier(Box<'a, JSXIdentifier<'a>>), MemberExpression(Box<'a, JSXMemberExpression<'a>>), } @@ -203,7 +203,7 @@ pub struct JSXSpreadAttribute<'a> { #[cfg_attr(feature = "serialize", derive(Serialize, Tsify))] #[cfg_attr(feature = "serialize", serde(untagged))] pub enum JSXAttributeName<'a> { - Identifier(JSXIdentifier<'a>), + Identifier(Box<'a, JSXIdentifier<'a>>), NamespacedName(Box<'a, JSXNamespacedName<'a>>), } @@ -212,8 +212,8 @@ pub enum JSXAttributeName<'a> { #[cfg_attr(feature = "serialize", derive(Serialize, Tsify))] #[cfg_attr(feature = "serialize", serde(untagged))] pub enum JSXAttributeValue<'a> { - StringLiteral(StringLiteral<'a>), - ExpressionContainer(JSXExpressionContainer<'a>), + StringLiteral(Box<'a, StringLiteral<'a>>), + ExpressionContainer(Box<'a, JSXExpressionContainer<'a>>), Element(Box<'a, JSXElement<'a>>), Fragment(Box<'a, JSXFragment<'a>>), } @@ -240,11 +240,11 @@ impl<'a> JSXIdentifier<'a> { #[cfg_attr(feature = "serialize", derive(Serialize, Tsify))] #[cfg_attr(feature = "serialize", serde(untagged))] pub enum JSXChild<'a> { - Text(JSXText<'a>), + Text(Box<'a, JSXText<'a>>), Element(Box<'a, JSXElement<'a>>), Fragment(Box<'a, JSXFragment<'a>>), - ExpressionContainer(JSXExpressionContainer<'a>), - Spread(JSXSpreadChild<'a>), + ExpressionContainer(Box<'a, JSXExpressionContainer<'a>>), + Spread(Box<'a, JSXSpreadChild<'a>>), } #[derive(Debug, Hash)] diff --git a/crates/oxc_ast/src/ast_builder.rs b/crates/oxc_ast/src/ast_builder.rs index 4c52578eb..d59c1aa84 100644 --- a/crates/oxc_ast/src/ast_builder.rs +++ b/crates/oxc_ast/src/ast_builder.rs @@ -1302,12 +1302,16 @@ impl<'a> AstBuilder<'a> { &self, span: Span, expression: JSXExpression<'a>, - ) -> JSXExpressionContainer<'a> { - JSXExpressionContainer { span, expression } + ) -> Box<'a, JSXExpressionContainer<'a>> { + self.alloc(JSXExpressionContainer { span, expression }) } - pub fn jsx_spread_child(&self, span: Span, expression: Expression<'a>) -> JSXSpreadChild<'a> { - JSXSpreadChild { span, expression } + pub fn jsx_spread_child( + &self, + span: Span, + expression: Expression<'a>, + ) -> Box<'a, JSXSpreadChild<'a>> { + self.alloc(JSXSpreadChild { span, expression }) } pub fn jsx_empty_expression(&self, span: Span) -> JSXEmptyExpression { @@ -1335,8 +1339,8 @@ impl<'a> AstBuilder<'a> { JSXIdentifier { span, name } } - pub fn jsx_text(&self, span: Span, value: Atom<'a>) -> JSXText<'a> { - JSXText { span, value } + pub fn jsx_text(&self, span: Span, value: Atom<'a>) -> Box<'a, JSXText<'a>> { + self.alloc(JSXText { span, value }) } /* ---------- TypeScript ---------- */ diff --git a/crates/oxc_linter/src/rules/jsx_a11y/alt_text.rs b/crates/oxc_linter/src/rules/jsx_a11y/alt_text.rs index ce33a3c26..0c8a06719 100644 --- a/crates/oxc_linter/src/rules/jsx_a11y/alt_text.rs +++ b/crates/oxc_linter/src/rules/jsx_a11y/alt_text.rs @@ -1,8 +1,5 @@ use oxc_ast::{ - ast::{ - JSXAttributeItem, JSXAttributeValue, JSXElement, JSXExpression, JSXExpressionContainer, - JSXOpeningElement, - }, + ast::{JSXAttributeItem, JSXAttributeValue, JSXElement, JSXExpression, JSXOpeningElement}, AstKind, }; use oxc_diagnostics::{ @@ -212,10 +209,13 @@ impl Rule for AltText { fn is_valid_alt_prop(item: &JSXAttributeItem<'_>) -> bool { match get_prop_value(item) { None => false, - Some(JSXAttributeValue::ExpressionContainer(JSXExpressionContainer { - expression: JSXExpression::Expression(expr), - .. - })) => !expr.is_null_or_undefined(), + Some(JSXAttributeValue::ExpressionContainer(container)) => { + if let JSXExpression::Expression(expr) = &container.expression { + !expr.is_null_or_undefined() + } else { + true + } + } _ => true, } } @@ -229,10 +229,13 @@ fn aria_label_has_value<'a>(item: &'a JSXAttributeItem<'a>) -> bool { match get_prop_value(item) { None => false, Some(JSXAttributeValue::StringLiteral(s)) if s.value.is_empty() => false, - Some(JSXAttributeValue::ExpressionContainer(JSXExpressionContainer { - expression: JSXExpression::Expression(expr), - .. - })) => !expr.is_undefined(), + Some(JSXAttributeValue::ExpressionContainer(container)) => { + if let JSXExpression::Expression(expr) = &container.expression { + !expr.is_undefined() + } else { + true + } + } _ => true, } } diff --git a/crates/oxc_linter/src/rules/jsx_a11y/aria_role.rs b/crates/oxc_linter/src/rules/jsx_a11y/aria_role.rs index 0e1bba5fc..f21d2c38b 100644 --- a/crates/oxc_linter/src/rules/jsx_a11y/aria_role.rs +++ b/crates/oxc_linter/src/rules/jsx_a11y/aria_role.rs @@ -1,5 +1,5 @@ use oxc_ast::{ - ast::{JSXAttributeValue, JSXExpression, JSXExpressionContainer}, + ast::{JSXAttributeValue, JSXExpression}, AstKind, }; use oxc_diagnostics::{ @@ -134,12 +134,11 @@ impl Rule for AriaRole { }; match get_prop_value(aria_role) { - Some(JSXAttributeValue::ExpressionContainer(JSXExpressionContainer { - expression: JSXExpression::Expression(expr), - .. - })) => { - if expr.is_undefined() || expr.is_null() { - ctx.diagnostic(AriaRoleDiagnostic(attr.span, String::new())); + Some(JSXAttributeValue::ExpressionContainer(container)) => { + if let JSXExpression::Expression(expr) = &container.expression { + if expr.is_undefined() || expr.is_null() { + ctx.diagnostic(AriaRoleDiagnostic(attr.span, String::new())); + } } } Some(JSXAttributeValue::StringLiteral(str)) => { diff --git a/crates/oxc_linter/src/rules/jsx_a11y/html_has_lang.rs b/crates/oxc_linter/src/rules/jsx_a11y/html_has_lang.rs index 618dd4992..20396ea7c 100644 --- a/crates/oxc_linter/src/rules/jsx_a11y/html_has_lang.rs +++ b/crates/oxc_linter/src/rules/jsx_a11y/html_has_lang.rs @@ -1,7 +1,5 @@ use oxc_ast::{ - ast::{ - JSXAttributeItem, JSXAttributeValue, JSXElementName, JSXExpression, JSXExpressionContainer, - }, + ast::{JSXAttributeItem, JSXAttributeValue, JSXElementName, JSXExpression}, AstKind, }; use oxc_diagnostics::{ @@ -87,10 +85,13 @@ impl Rule for HtmlHasLang { fn is_valid_lang_prop(item: &JSXAttributeItem) -> bool { match get_prop_value(item) { - Some(JSXAttributeValue::ExpressionContainer(JSXExpressionContainer { - expression: JSXExpression::Expression(expr), - .. - })) => !expr.is_undefined(), + Some(JSXAttributeValue::ExpressionContainer(container)) => { + if let JSXExpression::Expression(expr) = &container.expression { + !expr.is_undefined() + } else { + true + } + } Some(JSXAttributeValue::StringLiteral(str)) => !str.value.as_str().is_empty(), _ => true, } diff --git a/crates/oxc_linter/src/rules/jsx_a11y/iframe_has_title.rs b/crates/oxc_linter/src/rules/jsx_a11y/iframe_has_title.rs index 2c3e9eec7..158d49c9e 100644 --- a/crates/oxc_linter/src/rules/jsx_a11y/iframe_has_title.rs +++ b/crates/oxc_linter/src/rules/jsx_a11y/iframe_has_title.rs @@ -1,5 +1,5 @@ use oxc_ast::{ - ast::{Expression, JSXAttributeValue, JSXElementName, JSXExpression, JSXExpressionContainer}, + ast::{Expression, JSXAttributeValue, JSXElementName, JSXExpression}, AstKind, }; use oxc_diagnostics::{ @@ -88,28 +88,27 @@ impl Rule for IframeHasTitle { return; } } - Some(JSXAttributeValue::ExpressionContainer(JSXExpressionContainer { - expression: JSXExpression::Expression(expr), - .. - })) => { - if expr.is_string_literal() { - if let Expression::StringLiteral(str) = expr { - if !str.value.as_str().is_empty() { - return; + Some(JSXAttributeValue::ExpressionContainer(container)) => { + if let JSXExpression::Expression(expr) = &container.expression { + if expr.is_string_literal() { + if let Expression::StringLiteral(str) = expr { + if !str.value.as_str().is_empty() { + return; + } + } + if let Expression::TemplateLiteral(tmpl) = expr { + if !tmpl.quasis.is_empty() + & !tmpl.expressions.is_empty() + & tmpl.quasis.iter().any(|q| !q.value.raw.as_str().is_empty()) + { + return; + } } } - if let Expression::TemplateLiteral(tmpl) = expr { - if !tmpl.quasis.is_empty() - & !tmpl.expressions.is_empty() - & tmpl.quasis.iter().any(|q| !q.value.raw.as_str().is_empty()) - { - return; - } - } - } - if expr.is_identifier_reference() & !expr.is_undefined() { - return; + if expr.is_identifier_reference() & !expr.is_undefined() { + return; + } } } _ => {} diff --git a/crates/oxc_linter/src/rules/jsx_a11y/img_redundant_alt.rs b/crates/oxc_linter/src/rules/jsx_a11y/img_redundant_alt.rs index 7c52ebe5b..262b5c1d6 100644 --- a/crates/oxc_linter/src/rules/jsx_a11y/img_redundant_alt.rs +++ b/crates/oxc_linter/src/rules/jsx_a11y/img_redundant_alt.rs @@ -1,10 +1,7 @@ use regex::Regex; use oxc_ast::{ - ast::{ - Expression, JSXAttributeItem, JSXAttributeName, JSXAttributeValue, JSXExpression, - JSXExpressionContainer, - }, + ast::{Expression, JSXAttributeItem, JSXAttributeName, JSXAttributeValue, JSXExpression}, AstKind, }; use oxc_diagnostics::{ @@ -149,18 +146,15 @@ impl Rule for ImgRedundantAlt { ctx.diagnostic(ImgRedundantAltDiagnostic(alt_attribute_name_span)); } } - JSXAttributeValue::ExpressionContainer(JSXExpressionContainer { - expression: JSXExpression::Expression(expression), - .. - }) => match expression { - Expression::StringLiteral(lit) => { + JSXAttributeValue::ExpressionContainer(container) => match &container.expression { + JSXExpression::Expression(Expression::StringLiteral(lit)) => { let alt_text = lit.value.as_str(); if is_redundant_alt_text(alt_text, &self.redundant_words) { ctx.diagnostic(ImgRedundantAltDiagnostic(alt_attribute_name_span)); } } - Expression::TemplateLiteral(lit) => { + JSXExpression::Expression(Expression::TemplateLiteral(lit)) => { for quasi in &lit.quasis { let alt_text = quasi.value.raw.as_str(); diff --git a/crates/oxc_linter/src/rules/jsx_a11y/lang.rs b/crates/oxc_linter/src/rules/jsx_a11y/lang.rs index d62665fd7..c36775c73 100644 --- a/crates/oxc_linter/src/rules/jsx_a11y/lang.rs +++ b/crates/oxc_linter/src/rules/jsx_a11y/lang.rs @@ -1,8 +1,6 @@ use language_tags::LanguageTag; use oxc_ast::{ - ast::{ - JSXAttributeItem, JSXAttributeValue, JSXElementName, JSXExpression, JSXExpressionContainer, - }, + ast::{JSXAttributeItem, JSXAttributeValue, JSXElementName, JSXExpression}, AstKind, }; use oxc_diagnostics::{ @@ -94,10 +92,13 @@ impl Rule for Lang { fn is_valid_lang_prop(item: &JSXAttributeItem) -> bool { match get_prop_value(item) { - Some(JSXAttributeValue::ExpressionContainer(JSXExpressionContainer { - expression: JSXExpression::Expression(expr), - .. - })) => !expr.is_undefined(), + Some(JSXAttributeValue::ExpressionContainer(container)) => { + if let JSXExpression::Expression(expr) = &container.expression { + !expr.is_undefined() + } else { + true + } + } Some(JSXAttributeValue::StringLiteral(str)) => { let language_tag = LanguageTag::parse(str.value.as_str()).unwrap(); language_tag.is_valid() diff --git a/crates/oxc_linter/src/rules/jsx_a11y/mouse_events_have_key_events.rs b/crates/oxc_linter/src/rules/jsx_a11y/mouse_events_have_key_events.rs index 3ae4b4826..dc1f8cf09 100644 --- a/crates/oxc_linter/src/rules/jsx_a11y/mouse_events_have_key_events.rs +++ b/crates/oxc_linter/src/rules/jsx_a11y/mouse_events_have_key_events.rs @@ -1,5 +1,5 @@ use oxc_ast::{ - ast::{JSXAttributeValue, JSXExpression, JSXExpressionContainer}, + ast::{JSXAttributeValue, JSXExpression}, AstKind, }; use oxc_diagnostics::{ @@ -119,15 +119,14 @@ impl Rule for MouseEventsHaveKeyEvents { } match has_jsx_prop(jsx_opening_el, "onFocus").and_then(get_prop_value) { - Some(JSXAttributeValue::ExpressionContainer(JSXExpressionContainer { - expression: JSXExpression::Expression(expr), - .. - })) => { - if expr.is_undefined() { - ctx.diagnostic(MouseEventsHaveKeyEventsDiagnostic::MissOnFocus( - jsx_attr.span(), - String::from(handler), - )); + Some(JSXAttributeValue::ExpressionContainer(container)) => { + if let JSXExpression::Expression(expr) = &container.expression { + if expr.is_undefined() { + ctx.diagnostic(MouseEventsHaveKeyEventsDiagnostic::MissOnFocus( + jsx_attr.span(), + String::from(handler), + )); + } } } None => { @@ -150,15 +149,14 @@ impl Rule for MouseEventsHaveKeyEvents { } match has_jsx_prop(jsx_opening_el, "onBlur").and_then(get_prop_value) { - Some(JSXAttributeValue::ExpressionContainer(JSXExpressionContainer { - expression: JSXExpression::Expression(expr), - .. - })) => { - if expr.is_undefined() { - ctx.diagnostic(MouseEventsHaveKeyEventsDiagnostic::MissOnBlur( - jsx_attr.span(), - String::from(handler), - )); + Some(JSXAttributeValue::ExpressionContainer(container)) => { + if let JSXExpression::Expression(expr) = &container.expression { + if expr.is_undefined() { + ctx.diagnostic(MouseEventsHaveKeyEventsDiagnostic::MissOnBlur( + jsx_attr.span(), + String::from(handler), + )); + } } } None => { diff --git a/crates/oxc_linter/src/rules/jsx_a11y/no_access_key.rs b/crates/oxc_linter/src/rules/jsx_a11y/no_access_key.rs index 5130354ec..75d99a7b7 100644 --- a/crates/oxc_linter/src/rules/jsx_a11y/no_access_key.rs +++ b/crates/oxc_linter/src/rules/jsx_a11y/no_access_key.rs @@ -1,5 +1,5 @@ use oxc_ast::{ - ast::{JSXAttributeItem, JSXAttributeValue, JSXExpression, JSXExpressionContainer}, + ast::{JSXAttributeItem, JSXAttributeValue, JSXExpression}, AstKind, }; use oxc_diagnostics::{ @@ -48,14 +48,13 @@ impl Rule for NoAccessKey { Some(JSXAttributeValue::StringLiteral(_)) => { ctx.diagnostic(NoAccessKeyDiagnostic(attr.span)); } - Some(JSXAttributeValue::ExpressionContainer(JSXExpressionContainer { - expression: JSXExpression::Expression(expr), - .. - })) => { - if expr.is_identifier_reference() & expr.is_undefined() { - return; + Some(JSXAttributeValue::ExpressionContainer(container)) => { + if let JSXExpression::Expression(expr) = &container.expression { + if expr.is_identifier_reference() & expr.is_undefined() { + return; + } + ctx.diagnostic(NoAccessKeyDiagnostic(attr.span)); } - ctx.diagnostic(NoAccessKeyDiagnostic(attr.span)); } _ => {} } diff --git a/crates/oxc_linter/src/rules/nextjs/no_before_interactive_script_outside_document.rs b/crates/oxc_linter/src/rules/nextjs/no_before_interactive_script_outside_document.rs index 04c8c95fb..333f5271b 100644 --- a/crates/oxc_linter/src/rules/nextjs/no_before_interactive_script_outside_document.rs +++ b/crates/oxc_linter/src/rules/nextjs/no_before_interactive_script_outside_document.rs @@ -1,5 +1,5 @@ use oxc_ast::{ - ast::{JSXAttributeItem, JSXAttributeName, JSXAttributeValue, JSXElementName, JSXIdentifier}, + ast::{JSXAttributeItem, JSXAttributeName, JSXAttributeValue, JSXElementName}, AstKind, }; use oxc_diagnostics::{ @@ -48,8 +48,9 @@ impl Rule for NoBeforeInteractiveScriptOutsideDocument { if is_in_app_dir(file_path) { return; } - let JSXElementName::Identifier(JSXIdentifier { name: tag_name, .. }) = &jsx_el.name - else { + let tag_name = if let JSXElementName::Identifier(ident) = &jsx_el.name { + &ident.name + } else { return; }; if jsx_el.attributes.len() == 0 { diff --git a/crates/oxc_linter/src/rules/nextjs/no_unwanted_polyfillio.rs b/crates/oxc_linter/src/rules/nextjs/no_unwanted_polyfillio.rs index 235ac6233..fb11ffefd 100644 --- a/crates/oxc_linter/src/rules/nextjs/no_unwanted_polyfillio.rs +++ b/crates/oxc_linter/src/rules/nextjs/no_unwanted_polyfillio.rs @@ -1,5 +1,5 @@ use oxc_ast::{ - ast::{JSXAttributeItem, JSXAttributeName, JSXAttributeValue, JSXElementName, JSXIdentifier}, + ast::{JSXAttributeItem, JSXAttributeName, JSXAttributeValue, JSXElementName}, AstKind, }; use oxc_diagnostics::{ @@ -111,8 +111,9 @@ const NEXT_POLYFILLED_FEATURES: Set<&'static str> = phf_set! { impl Rule for NoUnwantedPolyfillio { fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { if let AstKind::JSXOpeningElement(jsx_el) = node.kind() { - let JSXElementName::Identifier(JSXIdentifier { name: tag_name, .. }) = &jsx_el.name - else { + let tag_name = if let JSXElementName::Identifier(ident) = &jsx_el.name { + &ident.name + } else { return; }; diff --git a/crates/oxc_linter/src/rules/react/button_has_type.rs b/crates/oxc_linter/src/rules/react/button_has_type.rs index 637700eef..cf4915cd7 100644 --- a/crates/oxc_linter/src/rules/react/button_has_type.rs +++ b/crates/oxc_linter/src/rules/react/button_has_type.rs @@ -1,7 +1,7 @@ use oxc_ast::{ ast::{ Argument, Expression, JSXAttributeItem, JSXAttributeValue, JSXElementName, JSXExpression, - JSXExpressionContainer, ObjectPropertyKind, + ObjectPropertyKind, }, AstKind, }; @@ -163,10 +163,13 @@ impl Rule for ButtonHasType { impl ButtonHasType { fn is_valid_button_type_prop(&self, item: &JSXAttributeItem) -> bool { match get_prop_value(item) { - Some(JSXAttributeValue::ExpressionContainer(JSXExpressionContainer { - expression: JSXExpression::Expression(expr), - .. - })) => self.is_valid_button_type_prop_expression(expr), + Some(JSXAttributeValue::ExpressionContainer(container)) => { + if let JSXExpression::Expression(expr) = &container.expression { + self.is_valid_button_type_prop_expression(expr) + } else { + false + } + } Some(JSXAttributeValue::StringLiteral(str)) => { self.is_valid_button_type_prop_string_literal(str.value.as_str()) } diff --git a/crates/oxc_linter/src/rules/react_perf/jsx_no_jsx_as_prop.rs b/crates/oxc_linter/src/rules/react_perf/jsx_no_jsx_as_prop.rs index d6c8a72c4..fece8ae75 100644 --- a/crates/oxc_linter/src/rules/react_perf/jsx_no_jsx_as_prop.rs +++ b/crates/oxc_linter/src/rules/react_perf/jsx_no_jsx_as_prop.rs @@ -1,5 +1,5 @@ use oxc_ast::{ - ast::{Expression, JSXAttributeValue, JSXElement, JSXExpression, JSXExpressionContainer}, + ast::{Expression, JSXAttributeValue, JSXElement, JSXExpression}, AstKind, }; use oxc_diagnostics::{ @@ -52,12 +52,11 @@ fn check_jsx_element<'a>(jsx_elem: &JSXElement<'a>, ctx: &LintContext<'a>) { for item in &jsx_elem.opening_element.attributes { match get_prop_value(item) { None => return, - Some(JSXAttributeValue::ExpressionContainer(JSXExpressionContainer { - expression: JSXExpression::Expression(expr), - .. - })) => { - if let Some(span) = check_expression(expr) { - ctx.diagnostic(JsxNoJsxAsPropDiagnostic(span)); + Some(JSXAttributeValue::ExpressionContainer(container)) => { + if let JSXExpression::Expression(expr) = &container.expression { + if let Some(span) = check_expression(expr) { + ctx.diagnostic(JsxNoJsxAsPropDiagnostic(span)); + } } } _ => {} diff --git a/crates/oxc_linter/src/rules/react_perf/jsx_no_new_array_as_prop.rs b/crates/oxc_linter/src/rules/react_perf/jsx_no_new_array_as_prop.rs index 39b8ec800..a3671b241 100644 --- a/crates/oxc_linter/src/rules/react_perf/jsx_no_new_array_as_prop.rs +++ b/crates/oxc_linter/src/rules/react_perf/jsx_no_new_array_as_prop.rs @@ -1,5 +1,5 @@ use oxc_ast::{ - ast::{Expression, JSXAttributeValue, JSXElement, JSXExpression, JSXExpressionContainer}, + ast::{Expression, JSXAttributeValue, JSXElement, JSXExpression}, AstKind, }; use oxc_diagnostics::{ @@ -58,12 +58,11 @@ fn check_jsx_element<'a>(jsx_elem: &JSXElement<'a>, ctx: &LintContext<'a>) { for item in &jsx_elem.opening_element.attributes { match get_prop_value(item) { None => return, - Some(JSXAttributeValue::ExpressionContainer(JSXExpressionContainer { - expression: JSXExpression::Expression(expr), - .. - })) => { - if let Some(span) = check_expression(expr) { - ctx.diagnostic(JsxNoNewArrayAsPropDiagnostic(span)); + Some(JSXAttributeValue::ExpressionContainer(container)) => { + if let JSXExpression::Expression(expr) = &container.expression { + if let Some(span) = check_expression(expr) { + ctx.diagnostic(JsxNoNewArrayAsPropDiagnostic(span)); + } } } _ => {} diff --git a/crates/oxc_linter/src/rules/react_perf/jsx_no_new_function_as_prop.rs b/crates/oxc_linter/src/rules/react_perf/jsx_no_new_function_as_prop.rs index add9a7ae8..825948098 100644 --- a/crates/oxc_linter/src/rules/react_perf/jsx_no_new_function_as_prop.rs +++ b/crates/oxc_linter/src/rules/react_perf/jsx_no_new_function_as_prop.rs @@ -1,8 +1,5 @@ use oxc_ast::{ - ast::{ - Expression, JSXAttributeValue, JSXElement, JSXExpression, JSXExpressionContainer, - MemberExpression, - }, + ast::{Expression, JSXAttributeValue, JSXElement, JSXExpression, MemberExpression}, AstKind, }; use oxc_diagnostics::{ @@ -56,12 +53,11 @@ fn check_jsx_element<'a>(jsx_elem: &JSXElement<'a>, ctx: &LintContext<'a>) { for item in &jsx_elem.opening_element.attributes { match get_prop_value(item) { None => return, - Some(JSXAttributeValue::ExpressionContainer(JSXExpressionContainer { - expression: JSXExpression::Expression(expr), - .. - })) => { - if let Some(span) = check_expression(expr) { - ctx.diagnostic(JsxNoNewFunctionAsPropDiagnostic(span)); + Some(JSXAttributeValue::ExpressionContainer(container)) => { + if let JSXExpression::Expression(expr) = &container.expression { + if let Some(span) = check_expression(expr) { + ctx.diagnostic(JsxNoNewFunctionAsPropDiagnostic(span)); + } } } _ => {} diff --git a/crates/oxc_linter/src/rules/react_perf/jsx_no_new_object_as_prop.rs b/crates/oxc_linter/src/rules/react_perf/jsx_no_new_object_as_prop.rs index 376562a05..f7985ade1 100644 --- a/crates/oxc_linter/src/rules/react_perf/jsx_no_new_object_as_prop.rs +++ b/crates/oxc_linter/src/rules/react_perf/jsx_no_new_object_as_prop.rs @@ -1,5 +1,5 @@ use oxc_ast::{ - ast::{Expression, JSXAttributeValue, JSXElement, JSXExpression, JSXExpressionContainer}, + ast::{Expression, JSXAttributeValue, JSXElement, JSXExpression}, AstKind, }; use oxc_diagnostics::{ @@ -57,12 +57,11 @@ fn check_jsx_element<'a>(jsx_elem: &JSXElement<'a>, ctx: &LintContext<'a>) { for item in &jsx_elem.opening_element.attributes { match get_prop_value(item) { None => return, - Some(JSXAttributeValue::ExpressionContainer(JSXExpressionContainer { - expression: JSXExpression::Expression(expr), - .. - })) => { - if let Some(span) = check_expression(expr) { - ctx.diagnostic(JsxNoNewObjectAsPropDiagnostic(span)); + Some(JSXAttributeValue::ExpressionContainer(container)) => { + if let JSXExpression::Expression(expr) = &container.expression { + if let Some(span) = check_expression(expr) { + ctx.diagnostic(JsxNoNewObjectAsPropDiagnostic(span)); + } } } _ => {} diff --git a/crates/oxc_linter/src/utils/react.rs b/crates/oxc_linter/src/utils/react.rs index f73975a1a..d92b6c468 100644 --- a/crates/oxc_linter/src/utils/react.rs +++ b/crates/oxc_linter/src/utils/react.rs @@ -1,8 +1,7 @@ use oxc_ast::{ ast::{ CallExpression, Expression, JSXAttributeItem, JSXAttributeName, JSXAttributeValue, - JSXChild, JSXElement, JSXElementName, JSXExpression, JSXExpressionContainer, - JSXOpeningElement, + JSXChild, JSXElement, JSXElementName, JSXExpression, JSXOpeningElement, }, AstKind, }; @@ -94,10 +93,13 @@ pub fn is_hidden_from_screen_reader(ctx: &LintContext, node: &JSXOpeningElement) has_jsx_prop_lowercase(node, "aria-hidden").map_or(false, |v| match get_prop_value(v) { None => true, Some(JSXAttributeValue::StringLiteral(s)) if s.value == "true" => true, - Some(JSXAttributeValue::ExpressionContainer(JSXExpressionContainer { - expression: JSXExpression::Expression(expr), - .. - })) => expr.get_boolean_value().unwrap_or(false), + Some(JSXAttributeValue::ExpressionContainer(container)) => { + if let JSXExpression::Expression(expr) = &container.expression { + expr.get_boolean_value().unwrap_or(false) + } else { + false + } + } _ => false, }) } @@ -107,10 +109,13 @@ pub fn object_has_accessible_child(ctx: &LintContext, node: &JSXElement<'_>) -> node.children.iter().any(|child| match child { JSXChild::Text(text) => !text.value.is_empty(), JSXChild::Element(el) => !is_hidden_from_screen_reader(ctx, &el.opening_element), - JSXChild::ExpressionContainer(JSXExpressionContainer { - expression: JSXExpression::Expression(expr), - .. - }) => !expr.is_undefined() && !expr.is_null(), + JSXChild::ExpressionContainer(container) => { + if let JSXExpression::Expression(expr) = &container.expression { + !expr.is_undefined() && !expr.is_null() + } else { + false + } + } _ => false, }) || has_jsx_prop_lowercase(&node.opening_element, "dangerouslySetInnerHTML").is_some() || has_jsx_prop_lowercase(&node.opening_element, "children").is_some() @@ -252,15 +257,14 @@ pub fn get_element_type(context: &LintContext, element: &JSXOpeningElement) -> O pub fn parse_jsx_value(value: &JSXAttributeValue) -> Result { match value { JSXAttributeValue::StringLiteral(str) => str.value.parse().or(Err(())), - JSXAttributeValue::ExpressionContainer(JSXExpressionContainer { - expression: JSXExpression::Expression(expression), - .. - }) => match expression { - Expression::StringLiteral(str) => str.value.parse().or(Err(())), - Expression::TemplateLiteral(tmpl) => { + JSXAttributeValue::ExpressionContainer(container) => match &container.expression { + JSXExpression::Expression(Expression::StringLiteral(str)) => { + str.value.parse().or(Err(())) + } + JSXExpression::Expression(Expression::TemplateLiteral(tmpl)) => { tmpl.quasis.first().unwrap().value.raw.parse().or(Err(())) } - Expression::NumericLiteral(num) => Ok(num.value), + JSXExpression::Expression(Expression::NumericLiteral(num)) => Ok(num.value), _ => Err(()), }, _ => Err(()), diff --git a/crates/oxc_parser/src/jsx/mod.rs b/crates/oxc_parser/src/jsx/mod.rs index 33fe6de56..f7b2ee65b 100644 --- a/crates/oxc_parser/src/jsx/mod.rs +++ b/crates/oxc_parser/src/jsx/mod.rs @@ -144,7 +144,7 @@ impl<'a> ParserImpl<'a> { .map(JSXElementName::MemberExpression); } - Ok(JSXElementName::Identifier(identifier)) + Ok(JSXElementName::Identifier(self.ast.alloc(identifier))) } /// `JSXMemberExpression` : @@ -156,7 +156,7 @@ impl<'a> ParserImpl<'a> { object: JSXIdentifier<'a>, ) -> Result>> { let mut span = span; - let mut object = JSXMemberExpressionObject::Identifier(object); + let mut object = JSXMemberExpressionObject::Identifier(self.ast.alloc(object)); let mut property = None; while self.eat(Kind::Dot) && !self.at(Kind::Eof) { @@ -214,10 +214,11 @@ impl<'a> ParserImpl<'a> { self.parse_jsx_spread_child().map(JSXChild::Spread).map(Some) } // {expr} - Kind::LCurly => self - .parse_jsx_expression_container(/* is_jsx_child */ true) - .map(JSXChild::ExpressionContainer) - .map(Some), + Kind::LCurly => { + self.parse_jsx_expression_container(/* is_jsx_child */ true) + .map(JSXChild::ExpressionContainer) + .map(Some) + } // text Kind::JSXText => Ok(Some(JSXChild::Text(self.parse_jsx_text()))), _ => Err(self.unexpected()), @@ -228,7 +229,7 @@ impl<'a> ParserImpl<'a> { fn parse_jsx_expression_container( &mut self, in_jsx_child: bool, - ) -> Result> { + ) -> Result>> { let span = self.start_span(); self.bump_any(); // bump `{` @@ -269,7 +270,7 @@ impl<'a> ParserImpl<'a> { /// `JSXChildExpression` : /// { ... `AssignmentExpression` } - fn parse_jsx_spread_child(&mut self) -> Result> { + fn parse_jsx_spread_child(&mut self) -> Result>> { let span = self.start_span(); self.bump_any(); // bump `{` self.expect(Kind::Dot3)?; @@ -336,12 +337,14 @@ impl<'a> ParserImpl<'a> { ))); } - Ok(JSXAttributeName::Identifier(identifier)) + Ok(JSXAttributeName::Identifier(self.ast.alloc(identifier))) } fn parse_jsx_attribute_value(&mut self) -> Result> { match self.cur_kind() { - Kind::Str => self.parse_literal_string().map(JSXAttributeValue::StringLiteral), + Kind::Str => self + .parse_literal_string() + .map(|str_lit| JSXAttributeValue::StringLiteral(self.ast.alloc(str_lit))), Kind::LCurly => { let expr = self.parse_jsx_expression_container(/* is_jsx_child */ false)?; Ok(JSXAttributeValue::ExpressionContainer(expr)) @@ -374,7 +377,7 @@ impl<'a> ParserImpl<'a> { Ok(self.ast.jsx_identifier(span, name.into())) } - fn parse_jsx_text(&mut self) -> JSXText<'a> { + fn parse_jsx_text(&mut self) -> Box<'a, JSXText<'a>> { let span = self.start_span(); let value = Atom::from(self.cur_string()); self.bump_any(); diff --git a/crates/oxc_transformer/src/react/jsx_self/mod.rs b/crates/oxc_transformer/src/react/jsx_self/mod.rs index 1e4385c1e..925e226db 100644 --- a/crates/oxc_transformer/src/react/jsx_self/mod.rs +++ b/crates/oxc_transformer/src/react/jsx_self/mod.rs @@ -66,7 +66,8 @@ impl<'a> ReactJsxSelf<'a> { } } - let name = JSXAttributeName::Identifier(JSXIdentifier::new(SPAN, SELF.into())); + let name = + JSXAttributeName::Identifier(self.ctx.ast.alloc(JSXIdentifier::new(SPAN, SELF.into()))); let value = { let jsx_expr = JSXExpression::Expression(self.ctx.ast.this_expression(SPAN)); let container = self.ctx.ast.jsx_expression_container(SPAN, jsx_expr); diff --git a/crates/oxc_transformer/src/react/jsx_source/mod.rs b/crates/oxc_transformer/src/react/jsx_source/mod.rs index 038387f56..3b9c01407 100644 --- a/crates/oxc_transformer/src/react/jsx_source/mod.rs +++ b/crates/oxc_transformer/src/react/jsx_source/mod.rs @@ -80,7 +80,9 @@ impl<'a> ReactJsxSource<'a> { self.should_add_jsx_file_name_variable = true; - let key = JSXAttributeName::Identifier(self.ctx.ast.jsx_identifier(SPAN, SOURCE.into())); + let key = JSXAttributeName::Identifier( + self.ctx.ast.alloc(self.ctx.ast.jsx_identifier(SPAN, SOURCE.into())), + ); let object = self.get_source_object(); let expr = self.ctx.ast.jsx_expression_container(SPAN, JSXExpression::Expression(object)); let value = JSXAttributeValue::ExpressionContainer(expr);