perf(linter): get fewer parent nodes in unicorn/prefer-dom-node-text-content (#6467)

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:

<img width="1147" alt="Screenshot 2024-10-12 at 3 05 05 AM" src="https://github.com/user-attachments/assets/4a551b04-370f-4ed9-b0d5-99d58b03235b">

After (-0.4% reduction in number of samples spent in this rule):

<img width="1146" alt="image" src="https://github.com/user-attachments/assets/340edc36-55cc-4bf4-aa8e-9a600848b798">
This commit is contained in:
camchenry 2024-10-13 14:17:08 +00:00
parent 6d041fb469
commit 725f9f6eb0

View file

@ -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"),
);
}
}
}
}
// `const {innerText} = node` or `({innerText: text} = node)`
AstKind::IdentifierName(identifier) => {
if identifier.name != "innerText" {
return;
}
let Some(parent_node) = ctx.nodes().parent_node(node.id()) else {
return;
};
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;
};
let Some(grand_parent_node) = ctx.nodes().parent_node(parent_node.id()) else {
return;
};
let parent_node_kind = parent_node.kind();
let grand_parent_node_kind = grand_parent_node.kind();
// `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));
}
}
_ => {}
}
}
}