perf(linter/unicorn/no-invalid-fetch-options): narrow AST dispatch (#28354)

Start from object literals used directly as the options argument,
preserving existing wrapper and property behavior. Reduce fixture
callbacks from 64,027 to 14,125.


---

<sub>Stack created with <a
href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a
href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub>

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Cam McHenryandCopilot authored and GitHub committed 2026-10-28 22:28:45 -04:00
1 parent 2ab73cc2f4
commit 7a1243ebee
3 files changed
+29 -29

No files matched your search

+1 -1
View File
@@ -3384,7 +3384,7 @@ impl RuleRunner for crate::rules::unicorn::no_instanceof_builtins::NoInstanceofB
impl RuleRunner for crate::rules::unicorn::no_invalid_fetch_options::NoInvalidFetchOptions {
const NODE_TYPES: Option<&AstTypesBitset> =
Some(&AstTypesBitset::from_types(&[AstType::CallExpression, AstType::NewExpression]));
Some(&AstTypesBitset::from_types(&[AstType::ObjectExpression]));
const RUN_FUNCTIONS: RuleRunFunctionsImplemented = RuleRunFunctionsImplemented::Run;
}
@@ -2,18 +2,17 @@ use std::borrow::Cow;
use crate::{LintContext, ast_util::is_new_expression, rule::Rule};
use cow_utils::CowUtils;
use oxc_allocator::ArenaBox;
use oxc_ast::{
AstKind,
ast::{
Argument, Expression, FormalParameter, ObjectExpression, ObjectPropertyKind, PropertyKey,
TSLiteral, TSLiteralType, TSType, TSTypeAnnotation, TemplateLiteral,
Expression, FormalParameter, ObjectExpression, ObjectPropertyKind, PropertyKey, TSLiteral,
TSLiteralType, TSType, TSTypeAnnotation, TemplateLiteral,
},
};
use oxc_diagnostics::OxcDiagnostic;
use oxc_macros::declare_oxc_lint;
use oxc_semantic::AstNode;
use oxc_span::Span;
use oxc_span::{GetSpan, Span};
use oxc_str::CompactStr;
fn no_invalid_fetch_options_diagnostic(span: Span, method: &str) -> OxcDiagnostic {
@@ -62,30 +61,25 @@ declare_oxc_lint!(
impl Rule for NoInvalidFetchOptions {
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
match node.kind() {
AstKind::CallExpression(call_expr) => {
if !call_expr.callee.is_specific_id("fetch") || call_expr.arguments.len() < 2 {
return;
}
if let Argument::ObjectExpression(expr) = &call_expr.arguments[1]
&& let Some((method_name, body_span)) = is_invalid_fetch_options(expr, ctx)
{
ctx.diagnostic(no_invalid_fetch_options_diagnostic(body_span, &method_name));
}
let AstKind::ObjectExpression(expr) = node.kind() else {
return;
};
let arguments = match ctx.nodes().parent_kind(node.id()) {
AstKind::CallExpression(call_expr) if call_expr.callee.is_specific_id("fetch") => {
&call_expr.arguments
}
AstKind::NewExpression(new_expr) => {
if !is_new_expression(new_expr, &["Request"], Some(2), None) {
return;
}
if let Argument::ObjectExpression(expr) = &new_expr.arguments[1]
&& let Some((method_name, body_span)) = is_invalid_fetch_options(expr, ctx)
{
ctx.diagnostic(no_invalid_fetch_options_diagnostic(body_span, &method_name));
}
AstKind::NewExpression(new_expr)
if is_new_expression(new_expr, &["Request"], Some(2), None) =>
{
&new_expr.arguments
}
_ => {}
_ => return,
};
if arguments.get(1).is_none_or(|argument| argument.span() != expr.span) {
return;
}
if let Some((method_name, body_span)) = is_invalid_fetch_options(expr, ctx) {
ctx.diagnostic(no_invalid_fetch_options_diagnostic(body_span, &method_name));
}
}
}
@@ -94,7 +88,7 @@ impl Rule for NoInvalidFetchOptions {
const UNKNOWN_METHOD_NAME: Cow<'static, str> = Cow::Borrowed("UNKNOWN");
fn is_invalid_fetch_options<'a>(
obj_expr: &'a ArenaBox<'_, ObjectExpression<'_>>,
obj_expr: &'a ObjectExpression<'_>,
ctx: &'a LintContext<'_>,
) -> Option<(Cow<'a, str>, Span)> {
// fetch and Request method defaults to "GET"
@@ -299,6 +293,12 @@ fn test() {
"new not_Request(url, {body})",
"fetch({body}, url)",
"new Request({body}, url)",
"fetch(url, {}, {body})",
"new Request(url, {}, {body})",
"fetch(url, ({body}))",
"new Request(url, ({body}))",
"fetch(url, {body} as RequestInit)",
"fetch(url, {options: {body}})",
r#"fetch(url, {[body]: "foo=bar"})"#,
r#"new Request(url, {[body]: "foo=bar"})"#,
r#"fetch(url, {body: "foo=bar", body: undefined});"#,
@@ -548,7 +548,7 @@ unicorn/no-hex-escape | 63282
unicorn/no-immediate-mutation | 24802
unicorn/no-instanceof-array | 20604
unicorn/no-instanceof-builtins | 20604
unicorn/no-invalid-fetch-options | 64027
unicorn/no-invalid-fetch-options | 14125
unicorn/no-invalid-remove-event-listener | 62606
unicorn/no-length-as-slice-end | 62606
unicorn/no-lonely-if | 13190