feat(linter): eslint-plugin-react-perf (#2086)

Relates #2041 

Closes #2042
Closes #2043
Closes #2044
Closes #2045
This commit is contained in:
Hulk 2024-01-22 13:53:48 +08:00 committed by GitHub
parent 4f59c4fdfc
commit 5ca07bcb09
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 695 additions and 1 deletions

View file

@ -163,6 +163,13 @@ mod react {
pub mod require_render_return;
}
mod react_perf {
pub mod no_jsx_as_prop;
pub mod no_new_array_as_prop;
pub mod no_new_function_as_props;
pub mod no_new_object_as_prop;
}
mod unicorn {
pub mod catch_error_name;
pub mod empty_brace_spaces;
@ -508,6 +515,10 @@ oxc_macros::declare_all_lint_rules! {
react::no_is_mounted,
react::no_unknown_property,
react::require_render_return,
react_perf::no_jsx_as_prop,
react_perf::no_new_array_as_prop,
react_perf::no_new_function_as_props,
react_perf::no_new_object_as_prop,
import::default,
import::no_named_as_default_member,
import::named,

View file

@ -0,0 +1,95 @@
use oxc_ast::{
ast::{Expression, JSXAttributeValue, JSXElement, JSXExpression, JSXExpressionContainer},
AstKind,
};
use oxc_diagnostics::{
miette::{self, Diagnostic},
thiserror::Error,
};
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;
use crate::{context::LintContext, rule::Rule, utils::get_prop_value, AstNode};
#[derive(Debug, Error, Diagnostic)]
#[error(
"eslint-plugin-react-perf(no-jsx-as-prop): JSX attribute values should not contain other JSX."
)]
#[diagnostic(severity(warning), help(r"simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array)."))]
struct NoJsxAsPropDiagnostic(#[label] pub Span);
#[derive(Debug, Default, Clone)]
pub struct NoJsxAsProp;
declare_oxc_lint!(
/// ### What it does
///
/// Prevent JSX that are local to the current method from being used as values of JSX props
///
/// ### Example
/// ```javascript
/// // Bad
/// <Item jsx={<SubItem />} />
/// <Item jsx={this.props.jsx || <SubItem />} />
/// <Item jsx={this.props.jsx ? this.props.jsx : <SubItem />} />
///
/// // Good
/// <Item callback={this.props.jsx} />
/// ```
NoJsxAsProp,
restriction
);
impl Rule for NoJsxAsProp {
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
if let AstKind::JSXElement(jsx_elem) = node.kind() {
check_jsx_element(jsx_elem, ctx);
}
}
}
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(NoJsxAsPropDiagnostic(span));
}
}
_ => {}
};
}
}
fn check_expression(expr: &Expression) -> Option<Span> {
match expr.without_parenthesized() {
Expression::JSXElement(expr) => Some(expr.span),
Expression::LogicalExpression(expr) => {
check_expression(&expr.left).or_else(|| check_expression(&expr.right))
}
Expression::ConditionalExpression(expr) => {
check_expression(&expr.consequent).or_else(|| check_expression(&expr.alternate))
}
_ => None,
}
}
#[test]
fn test() {
use crate::tester::Tester;
let pass = vec![r"<Item callback={this.props.jsx} />"];
let fail = vec![
r"<Item jsx={<SubItem />} />",
r"<Item jsx={this.props.jsx || <SubItem />} />",
r"<Item jsx={this.props.jsx ? this.props.jsx : <SubItem />} />",
r"<Item jsx={this.props.jsx || (this.props.component ? this.props.component : <SubItem />)} />",
];
Tester::new(NoJsxAsProp::NAME, pass, fail).test_and_snapshot();
}

View file

@ -0,0 +1,117 @@
use oxc_ast::{
ast::{Expression, JSXAttributeValue, JSXElement, JSXExpression, JSXExpressionContainer},
AstKind,
};
use oxc_diagnostics::{
miette::{self, Diagnostic},
thiserror::Error,
};
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;
use crate::{
context::LintContext,
rule::Rule,
utils::{get_prop_value, is_constructor_matching_name},
AstNode,
};
#[derive(Debug, Error, Diagnostic)]
#[error("eslint-plugin-react-perf(no-new-array-as-prop): JSX attribute values should not contain Arrays created in the same scope.")]
#[diagnostic(severity(warning), help(r"simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array)."))]
struct NoNewArrayAsPropDiagnostic(#[label] pub Span);
#[derive(Debug, Default, Clone)]
pub struct NoNewArrayAsProp;
declare_oxc_lint!(
/// ### What it does
///
/// Prevent Arrays that are local to the current method from being used as values of JSX props
///
/// ### Example
/// ```javascript
/// // Bad
/// <Item list={[]} />
/// <Item list={new Array()} />
/// <Item list={Array()} />
/// <Item list={this.props.list || []} />
/// <Item list={this.props.list ? this.props.list : []} />
///
/// // Good
/// <Item list={this.props.list} />
/// ```
NoNewArrayAsProp,
restriction
);
impl Rule for NoNewArrayAsProp {
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
if let AstKind::JSXElement(jsx_elem) = node.kind() {
check_jsx_element(jsx_elem, ctx);
}
}
}
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(NoNewArrayAsPropDiagnostic(span));
}
}
_ => {}
};
}
}
fn check_expression(expr: &Expression) -> Option<Span> {
match expr.without_parenthesized() {
Expression::ArrayExpression(expr) => Some(expr.span),
Expression::CallExpression(expr) => {
if is_constructor_matching_name(&expr.callee, "Array") {
Some(expr.span)
} else {
None
}
}
Expression::NewExpression(expr) => {
if is_constructor_matching_name(&expr.callee, "Array") {
Some(expr.span)
} else {
None
}
}
Expression::LogicalExpression(expr) => {
check_expression(&expr.left).or_else(|| check_expression(&expr.right))
}
Expression::ConditionalExpression(expr) => {
check_expression(&expr.consequent).or_else(|| check_expression(&expr.alternate))
}
_ => None,
}
}
#[test]
fn test() {
use crate::tester::Tester;
let pass = vec![r"<Item list={this.props.list} />"];
let fail = vec![
r"<Item list={[]} />",
r"<Item list={new Array()} />",
r"<Item list={Array()} />",
r"<Item list={this.props.list || []} />",
r"<Item list={this.props.list ? this.props.list : []} />",
r"<Item list={this.props.list || (this.props.arr ? this.props.arr : [])} />",
];
Tester::new(NoNewArrayAsProp::NAME, pass, fail).test_and_snapshot();
}

View file

@ -0,0 +1,143 @@
use oxc_ast::{
ast::{
Expression, JSXAttributeValue, JSXElement, JSXExpression, JSXExpressionContainer,
MemberExpression,
},
AstKind,
};
use oxc_diagnostics::{
miette::{self, Diagnostic},
thiserror::Error,
};
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;
use crate::{
context::LintContext,
rule::Rule,
utils::{get_prop_value, is_constructor_matching_name},
AstNode,
};
#[derive(Debug, Error, Diagnostic)]
#[error("eslint-plugin-react-perf(no-new-function-as-props): JSX attribute values should not contain functions created in the same scope.")]
#[diagnostic(severity(warning), help(r"simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array)."))]
struct NoNewFunctionAsPropsDiagnostic(#[label] pub Span);
#[derive(Debug, Default, Clone)]
pub struct NoNewFunctionAsProps;
declare_oxc_lint!(
/// ### What it does
///
/// Prevent Functions that are local to the current method from being used as values of JSX props
/// ### Example
/// ```javascript
/// // Bad
/// <Item callback={new Function(...)} />
/// <Item callback={this.props.callback || function() {}} />
///
/// // Good
/// <Item callback={this.props.callback} />
/// ```
NoNewFunctionAsProps,
restriction
);
impl Rule for NoNewFunctionAsProps {
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
if let AstKind::JSXElement(jsx_elem) = node.kind() {
check_jsx_element(jsx_elem, ctx);
}
}
}
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(NoNewFunctionAsPropsDiagnostic(span));
}
}
_ => {}
};
}
}
fn check_expression(expr: &Expression) -> Option<Span> {
match expr.without_parenthesized() {
Expression::ArrowExpression(expr) => Some(expr.span),
Expression::FunctionExpression(expr) => Some(expr.span),
Expression::CallExpression(expr) => {
if is_constructor_matching_name(&expr.callee, "Function") {
return Some(expr.span);
}
let Expression::MemberExpression(member_expr) = &expr.callee else {
return None;
};
let property_name = MemberExpression::static_property_name(member_expr);
if property_name == Some("bind") {
Some(expr.span)
} else {
None
}
}
Expression::NewExpression(expr) => {
if is_constructor_matching_name(&expr.callee, "Function") {
Some(expr.span)
} else {
None
}
}
Expression::LogicalExpression(expr) => {
check_expression(&expr.left).or_else(|| check_expression(&expr.right))
}
Expression::ConditionalExpression(expr) => {
check_expression(&expr.consequent).or_else(|| check_expression(&expr.alternate))
}
_ => None,
}
}
#[test]
fn test() {
use crate::tester::Tester;
let pass = vec![
r"<Item callback={this.props.callback} />",
r"<Item promise={new Promise()} />",
r"<Item onClick={bind(foo)} />",
r"<Item prop={0} />",
r"var a;<Item prop={a} />",
r"var a;a = 1;<Item prop={a} />",
r"var a;<Item prop={a} />",
r"function foo ({prop1 = function(){}, prop2}) {
return <Comp prop={prop2} />
}",
r"function foo ({prop1, prop2 = function(){}}) {
return <Comp prop={prop1} />
}",
];
let fail = vec![
r"<Item prop={function(){return true}} />",
r"<Item prop={() => true} />",
r"<Item prop={new Function('a', 'alert(a)')}/>",
r"<Item prop={Function()}/>",
r"<Item onClick={this.clickHandler.bind(this)} />",
r"<Item callback={this.props.callback || function() {}} />",
r"<Item callback={this.props.callback ? this.props.callback : function() {}} />",
r"<Item prop={this.props.callback || this.props.callback ? this.props.callback : function(){}} />",
r"<Item prop={this.props.callback || (this.props.cb ? this.props.cb : function(){})} />",
];
Tester::new(NoNewFunctionAsProps::NAME, pass, fail).test_and_snapshot();
}

View file

@ -0,0 +1,117 @@
use oxc_ast::{
ast::{Expression, JSXAttributeValue, JSXElement, JSXExpression, JSXExpressionContainer},
AstKind,
};
use oxc_diagnostics::{
miette::{self, Diagnostic},
thiserror::Error,
};
use oxc_macros::declare_oxc_lint;
use oxc_span::Span;
use crate::{
context::LintContext,
rule::Rule,
utils::{get_prop_value, is_constructor_matching_name},
AstNode,
};
#[derive(Debug, Error, Diagnostic)]
#[error("eslint-plugin-react-perf(no-new-object-as-prop): JSX attribute values should not contain objects created in the same scope.")]
#[diagnostic(severity(warning), help(r"simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array)."))]
struct NoNewObjectAsPropDiagnostic(#[label] pub Span);
#[derive(Debug, Default, Clone)]
pub struct NoNewObjectAsProp;
declare_oxc_lint!(
/// ### What it does
///
/// Prevent Objects that are local to the current method from being used as values of JSX props
///
/// ```javascript
/// // Bad
/// <Item config={{}} />
/// <Item config={new Object()} />
/// <Item config={Object()} />
/// <Item config={this.props.config || {}} />
/// <Item config={this.props.config ? this.props.config : {}} />
// <div style={{display: 'none'}} />
///
/// // Good
/// <Item config={staticConfig} />
/// ```
NoNewObjectAsProp,
restriction
);
impl Rule for NoNewObjectAsProp {
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
if let AstKind::JSXElement(jsx_elem) = node.kind() {
check_jsx_element(jsx_elem, ctx);
}
}
}
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(NoNewObjectAsPropDiagnostic(span));
}
}
_ => {}
};
}
}
fn check_expression(expr: &Expression) -> Option<Span> {
match expr.without_parenthesized() {
Expression::ObjectExpression(expr) => Some(expr.span),
Expression::CallExpression(expr) => {
if is_constructor_matching_name(&expr.callee, "Object") {
Some(expr.span)
} else {
None
}
}
Expression::NewExpression(expr) => {
if is_constructor_matching_name(&expr.callee, "Object") {
Some(expr.span)
} else {
None
}
}
Expression::LogicalExpression(expr) => {
check_expression(&expr.left).or_else(|| check_expression(&expr.right))
}
Expression::ConditionalExpression(expr) => {
check_expression(&expr.consequent).or_else(|| check_expression(&expr.alternate))
}
_ => None,
}
}
#[test]
fn test() {
use crate::tester::Tester;
let pass = vec![r"<Item config={staticConfig} />"];
let fail = vec![
r"<Item config={{}} />",
r"<Item config={new Object()} />",
r"<Item config={Object()} />",
r"<div style={{display: 'none'}} />",
r"<Item config={this.props.config || {}} />",
r"<Item config={this.props.config ? this.props.config : {}} />",
r"<Item config={this.props.config || (this.props.default ? this.props.default : {})} />",
];
Tester::new(NoNewObjectAsProp::NAME, pass, fail).test_and_snapshot();
}

View file

@ -0,0 +1,33 @@
---
source: crates/oxc_linter/src/tester.rs
expression: no_jsx_as_prop
---
⚠ eslint-plugin-react-perf(no-jsx-as-prop): JSX attribute values should not contain other JSX.
╭─[no_jsx_as_prop.tsx:1:1]
1 │ <Item jsx={<SubItem />} />
· ───────────
╰────
help: simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array).
⚠ eslint-plugin-react-perf(no-jsx-as-prop): JSX attribute values should not contain other JSX.
╭─[no_jsx_as_prop.tsx:1:1]
1 │ <Item jsx={this.props.jsx || <SubItem />} />
· ───────────
╰────
help: simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array).
⚠ eslint-plugin-react-perf(no-jsx-as-prop): JSX attribute values should not contain other JSX.
╭─[no_jsx_as_prop.tsx:1:1]
1 │ <Item jsx={this.props.jsx ? this.props.jsx : <SubItem />} />
· ───────────
╰────
help: simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array).
⚠ eslint-plugin-react-perf(no-jsx-as-prop): JSX attribute values should not contain other JSX.
╭─[no_jsx_as_prop.tsx:1:1]
1 │ <Item jsx={this.props.jsx || (this.props.component ? this.props.component : <SubItem />)} />
· ───────────
╰────
help: simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array).

View file

@ -0,0 +1,47 @@
---
source: crates/oxc_linter/src/tester.rs
expression: no_new_array_as_prop
---
⚠ eslint-plugin-react-perf(no-new-array-as-prop): JSX attribute values should not contain Arrays created in the same scope.
╭─[no_new_array_as_prop.tsx:1:1]
1 │ <Item list={[]} />
· ──
╰────
help: simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array).
⚠ eslint-plugin-react-perf(no-new-array-as-prop): JSX attribute values should not contain Arrays created in the same scope.
╭─[no_new_array_as_prop.tsx:1:1]
1 │ <Item list={new Array()} />
· ───────────
╰────
help: simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array).
⚠ eslint-plugin-react-perf(no-new-array-as-prop): JSX attribute values should not contain Arrays created in the same scope.
╭─[no_new_array_as_prop.tsx:1:1]
1 │ <Item list={Array()} />
· ───────
╰────
help: simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array).
⚠ eslint-plugin-react-perf(no-new-array-as-prop): JSX attribute values should not contain Arrays created in the same scope.
╭─[no_new_array_as_prop.tsx:1:1]
1 │ <Item list={this.props.list || []} />
· ──
╰────
help: simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array).
⚠ eslint-plugin-react-perf(no-new-array-as-prop): JSX attribute values should not contain Arrays created in the same scope.
╭─[no_new_array_as_prop.tsx:1:1]
1 │ <Item list={this.props.list ? this.props.list : []} />
· ──
╰────
help: simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array).
⚠ eslint-plugin-react-perf(no-new-array-as-prop): JSX attribute values should not contain Arrays created in the same scope.
╭─[no_new_array_as_prop.tsx:1:1]
1 │ <Item list={this.props.list || (this.props.arr ? this.props.arr : [])} />
· ──
╰────
help: simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array).

View file

@ -0,0 +1,68 @@
---
source: crates/oxc_linter/src/tester.rs
expression: no_new_function_as_props
---
⚠ eslint-plugin-react-perf(no-new-function-as-props): JSX attribute values should not contain functions created in the same scope.
╭─[no_new_function_as_props.tsx:1:1]
1 │ <Item prop={function(){return true}} />
· ───────────────────────
╰────
help: simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array).
⚠ eslint-plugin-react-perf(no-new-function-as-props): JSX attribute values should not contain functions created in the same scope.
╭─[no_new_function_as_props.tsx:1:1]
1 │ <Item prop={() => true} />
· ──────────
╰────
help: simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array).
⚠ eslint-plugin-react-perf(no-new-function-as-props): JSX attribute values should not contain functions created in the same scope.
╭─[no_new_function_as_props.tsx:1:1]
1 │ <Item prop={new Function('a', 'alert(a)')}/>
· ─────────────────────────────
╰────
help: simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array).
⚠ eslint-plugin-react-perf(no-new-function-as-props): JSX attribute values should not contain functions created in the same scope.
╭─[no_new_function_as_props.tsx:1:1]
1 │ <Item prop={Function()}/>
· ──────────
╰────
help: simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array).
⚠ eslint-plugin-react-perf(no-new-function-as-props): JSX attribute values should not contain functions created in the same scope.
╭─[no_new_function_as_props.tsx:1:1]
1 │ <Item onClick={this.clickHandler.bind(this)} />
· ────────────────────────────
╰────
help: simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array).
⚠ eslint-plugin-react-perf(no-new-function-as-props): JSX attribute values should not contain functions created in the same scope.
╭─[no_new_function_as_props.tsx:1:1]
1 │ <Item callback={this.props.callback || function() {}} />
· ─────────────
╰────
help: simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array).
⚠ eslint-plugin-react-perf(no-new-function-as-props): JSX attribute values should not contain functions created in the same scope.
╭─[no_new_function_as_props.tsx:1:1]
1 │ <Item callback={this.props.callback ? this.props.callback : function() {}} />
· ─────────────
╰────
help: simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array).
⚠ eslint-plugin-react-perf(no-new-function-as-props): JSX attribute values should not contain functions created in the same scope.
╭─[no_new_function_as_props.tsx:1:1]
1 │ <Item prop={this.props.callback || this.props.callback ? this.props.callback : function(){}} />
· ────────────
╰────
help: simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array).
⚠ eslint-plugin-react-perf(no-new-function-as-props): JSX attribute values should not contain functions created in the same scope.
╭─[no_new_function_as_props.tsx:1:1]
1 │ <Item prop={this.props.callback || (this.props.cb ? this.props.cb : function(){})} />
· ────────────
╰────
help: simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array).

View file

@ -0,0 +1,54 @@
---
source: crates/oxc_linter/src/tester.rs
expression: no_new_object_as_prop
---
⚠ eslint-plugin-react-perf(no-new-object-as-prop): JSX attribute values should not contain objects created in the same scope.
╭─[no_new_object_as_prop.tsx:1:1]
1 │ <Item config={{}} />
· ──
╰────
help: simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array).
⚠ eslint-plugin-react-perf(no-new-object-as-prop): JSX attribute values should not contain objects created in the same scope.
╭─[no_new_object_as_prop.tsx:1:1]
1 │ <Item config={new Object()} />
· ────────────
╰────
help: simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array).
⚠ eslint-plugin-react-perf(no-new-object-as-prop): JSX attribute values should not contain objects created in the same scope.
╭─[no_new_object_as_prop.tsx:1:1]
1 │ <Item config={Object()} />
· ────────
╰────
help: simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array).
⚠ eslint-plugin-react-perf(no-new-object-as-prop): JSX attribute values should not contain objects created in the same scope.
╭─[no_new_object_as_prop.tsx:1:1]
1 │ <div style={{display: 'none'}} />
· ─────────────────
╰────
help: simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array).
⚠ eslint-plugin-react-perf(no-new-object-as-prop): JSX attribute values should not contain objects created in the same scope.
╭─[no_new_object_as_prop.tsx:1:1]
1 │ <Item config={this.props.config || {}} />
· ──
╰────
help: simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array).
⚠ eslint-plugin-react-perf(no-new-object-as-prop): JSX attribute values should not contain objects created in the same scope.
╭─[no_new_object_as_prop.tsx:1:1]
1 │ <Item config={this.props.config ? this.props.config : {}} />
· ──
╰────
help: simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array).
⚠ eslint-plugin-react-perf(no-new-object-as-prop): JSX attribute values should not contain objects created in the same scope.
╭─[no_new_object_as_prop.tsx:1:1]
1 │ <Item config={this.props.config || (this.props.default ? this.props.default : {})} />
· ──
╰────
help: simplify props or memoize props in the parent component (https://react.dev/reference/react/memo#my-component-rerenders-when-a-prop-is-an-object-or-array).

View file

@ -1,6 +1,7 @@
mod jest;
mod node;
mod react;
mod react_perf;
mod unicorn;
pub use self::{jest::*, node::*, react::*, unicorn::*};
pub use self::{jest::*, node::*, react::*, react_perf::*, unicorn::*};

View file

@ -0,0 +1,8 @@
use oxc_ast::ast::Expression;
pub fn is_constructor_matching_name(callee: &Expression<'_>, name: &str) -> bool {
let Expression::Identifier(ident) = callee else {
return false;
};
ident.name == name
}