mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
perf(ast): box enum variants (#3058)
Box all enum variants for JSX types (`JSXAttributeName`, `JSXAttributeValue`, `JSXChild`, `JSXElementName`, `JSXMemberExpressionObject`). Part of #3047. I'm not sure how to interpret the benchmark results. As I said on #3047: > I imagine it may cost a little in performance in the parser due to extra calls to `alloc`, but in return traversing the AST should be cheaper, as the data is more compact, so less cache misses. Sure enough, there is a small impact (1%) on the 2 parser benchmarks for JSX files. However, the other benchmarks have too much noise in them to see whether this is repaid in a speed up on transformer etc, especially as the transformer benchmarks also include parsing. What do you think @Boshen?
This commit is contained in:
parent
68d082644c
commit
48e20880d4
21 changed files with 182 additions and 176 deletions
|
|
@ -83,7 +83,7 @@ pub struct JSXClosingFragment {
|
|||
#[cfg_attr(feature = "serialize", serde(untagged))]
|
||||
pub enum JSXElementName<'a> {
|
||||
/// `<Apple />`
|
||||
Identifier(JSXIdentifier<'a>),
|
||||
Identifier(Box<'a, JSXIdentifier<'a>>),
|
||||
/// `<Apple:Orange />`
|
||||
NamespacedName(Box<'a, JSXNamespacedName<'a>>),
|
||||
/// `<Apple.Orange />`
|
||||
|
|
@ -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)]
|
||||
|
|
|
|||
|
|
@ -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 ---------- */
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)) => {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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 => {
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
|||
|
|
@ -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<f64, ()> {
|
||||
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(()),
|
||||
|
|
|
|||
|
|
@ -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<Box<'a, JSXMemberExpression<'a>>> {
|
||||
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<JSXExpressionContainer<'a>> {
|
||||
) -> Result<Box<'a, JSXExpressionContainer<'a>>> {
|
||||
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<JSXSpreadChild<'a>> {
|
||||
fn parse_jsx_spread_child(&mut self) -> Result<Box<'a, JSXSpreadChild<'a>>> {
|
||||
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<JSXAttributeValue<'a>> {
|
||||
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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in a new issue