mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
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:
parent
6d041fb469
commit
725f9f6eb0
1 changed files with 51 additions and 41 deletions
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue