From 725f9f6eb04ed01e3b7551770412be3513545d71 Mon Sep 17 00:00:00 2001 From: camchenry <1514176+camchenry@users.noreply.github.com> Date: Sun, 13 Oct 2024 14:17:08 +0000 Subject: [PATCH] perf(linter): get fewer parent nodes in `unicorn/prefer-dom-node-text-content` (#6467) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Profiling showed that this rule was one of the slower ones, partially due to the fact that it was constantly calling `ctx.nodes()` and `ctx.nodes().parent_node()`. I've tried to fix this by reordering the logic so that we only fetch the parent nodes right before we need it. If we can early return, such as the identifier name not being `innerText`, or the node kind not being right, then we can skip fetching the parent. Before: Screenshot 2024-10-12 at 3 05 05 AM After (-0.4% reduction in number of samples spent in this rule): image --- .../unicorn/prefer_dom_node_text_content.rs | 92 ++++++++++--------- 1 file changed, 51 insertions(+), 41 deletions(-) diff --git a/crates/oxc_linter/src/rules/unicorn/prefer_dom_node_text_content.rs b/crates/oxc_linter/src/rules/unicorn/prefer_dom_node_text_content.rs index 78d148b1a55d4..0132e481d70b1 100644 --- a/crates/oxc_linter/src/rules/unicorn/prefer_dom_node_text_content.rs +++ b/crates/oxc_linter/src/rules/unicorn/prefer_dom_node_text_content.rs @@ -44,58 +44,68 @@ declare_oxc_lint!( impl Rule for PreferDomNodeTextContent { fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { - if let AstKind::MemberExpression(member_expr) = node.kind() { - if let Some((span, name)) = member_expr.static_property_info() { - if name == "innerText" && !member_expr.is_computed() { - ctx.diagnostic_with_fix( - prefer_dom_node_text_content_diagnostic(span), - |fixer| fixer.replace(span, "textContent"), - ); + match node.kind() { + AstKind::MemberExpression(member_expr) => { + if let Some((span, name)) = member_expr.static_property_info() { + if name == "innerText" && !member_expr.is_computed() { + ctx.diagnostic_with_fix( + prefer_dom_node_text_content_diagnostic(span), + |fixer| fixer.replace(span, "textContent"), + ); + } } } - } - - let Some(parent_node) = ctx.nodes().parent_node(node.id()) else { - return; - }; - - let Some(grand_parent_node) = ctx.nodes().parent_node(parent_node.id()) else { - return; - }; + // `const {innerText} = node` or `({innerText: text} = node)` + AstKind::IdentifierName(identifier) => { + if identifier.name != "innerText" { + return; + } - let parent_node_kind = parent_node.kind(); - let grand_parent_node_kind = grand_parent_node.kind(); + let mut ancestor_kinds = + ctx.nodes().iter_parents(node.id()).skip(1).map(AstNode::kind); + let (Some(parent_node_kind), Some(grand_parent_node_kind)) = + (ancestor_kinds.next(), ancestor_kinds.next()) + else { + return; + }; - // `const {innerText} = node` or `({innerText: text} = node)` - if let AstKind::IdentifierName(identifier) = node.kind() { - if identifier.name == "innerText" - && matches!(parent_node_kind, AstKind::PropertyKey(_)) - && (matches!(grand_parent_node_kind, AstKind::ObjectPattern(_)) - || matches!( - grand_parent_node_kind, - AstKind::ObjectAssignmentTarget(_) - | AstKind::SimpleAssignmentTarget(_) - | AstKind::AssignmentTarget(_) - )) - { - ctx.diagnostic(prefer_dom_node_text_content_diagnostic(identifier.span)); - return; + if matches!(parent_node_kind, AstKind::PropertyKey(_)) + && (matches!(grand_parent_node_kind, AstKind::ObjectPattern(_)) + || matches!( + grand_parent_node_kind, + AstKind::ObjectAssignmentTarget(_) + | AstKind::SimpleAssignmentTarget(_) + | AstKind::AssignmentTarget(_) + )) + { + ctx.diagnostic(prefer_dom_node_text_content_diagnostic(identifier.span)); + } } - } + // `({innerText} = node)` + AstKind::IdentifierReference(identifier_ref) => { + if identifier_ref.name != "innerText" { + return; + } - // `({innerText} = node)` - if let AstKind::IdentifierReference(identifier_ref) = node.kind() { - if identifier_ref.name == "innerText" - && matches!( + let mut ancestor_kinds = + ctx.nodes().iter_parents(node.id()).skip(1).map(AstNode::kind); + let (Some(parent_node_kind), Some(grand_parent_node_kind)) = + (ancestor_kinds.next(), ancestor_kinds.next()) + else { + return; + }; + + if matches!( parent_node_kind, AstKind::ObjectAssignmentTarget(_) | AstKind::AssignmentTarget(_) | AstKind::SimpleAssignmentTarget(_) - ) - && matches!(grand_parent_node_kind, AstKind::AssignmentTargetPattern(_)) - { - ctx.diagnostic(prefer_dom_node_text_content_diagnostic(identifier_ref.span)); + ) && matches!(grand_parent_node_kind, AstKind::AssignmentTargetPattern(_)) + { + ctx.diagnostic(prefer_dom_node_text_content_diagnostic(identifier_ref.span)); + } } + _ => {} } } }