diff --git a/crates/oxc_linter/src/ast_util.rs b/crates/oxc_linter/src/ast_util.rs index 79e2ef3e9..89cbecd79 100644 --- a/crates/oxc_linter/src/ast_util.rs +++ b/crates/oxc_linter/src/ast_util.rs @@ -316,6 +316,7 @@ pub fn extract_regex_flags<'a>( pub fn is_method_call<'a>( call_expr: &CallExpression<'a>, + objects: Option<&[&'a str]>, methods: Option<&[&'a str]>, min_arg_count: Option, max_arg_count: Option, @@ -337,6 +338,15 @@ pub fn is_method_call<'a>( return false; }; + if let Some(objects) = objects { + let Expression::Identifier(ident) = member_expr.object().without_parenthesized() else { + return false; + }; + if !objects.contains(&ident.name.as_str()) { + return false; + } + } + if let Some(methods) = methods { let Some(static_property_name) = member_expr.static_property_name() else { return false }; if !methods.contains(&static_property_name) { diff --git a/crates/oxc_linter/src/rules/unicorn/no_console_spaces.rs b/crates/oxc_linter/src/rules/unicorn/no_console_spaces.rs index d7e73f46b..959096d7b 100644 --- a/crates/oxc_linter/src/rules/unicorn/no_console_spaces.rs +++ b/crates/oxc_linter/src/rules/unicorn/no_console_spaces.rs @@ -9,7 +9,12 @@ use oxc_diagnostics::{ use oxc_macros::declare_oxc_lint; use oxc_span::{GetSpan, Span}; -use crate::{context::LintContext, rule::Rule, AstNode, Fix}; +use crate::{ + ast_util::{call_expr_method_callee_info, is_method_call}, + context::LintContext, + rule::Rule, + AstNode, Fix, +}; #[derive(Debug, Error, Diagnostic)] #[error( @@ -51,63 +56,61 @@ impl Rule for NoConsoleSpaces { _ => return, }; - let member_expr = match &call_expr.callee { - Expression::MemberExpression(member_expr) => member_expr, - _ => return, - }; + if !is_method_call( + call_expr, + Some(&["console"]), + Some(&["log", "debug", "info", "warn", "error"]), + None, + None, + ) { + return; + } - match member_expr.object() { - Expression::Identifier(ident) if ident.name == "console" => ident, - _ => return, - }; + let call_expr_arg_len = call_expr.arguments.len(); - if let Some(ident) = member_expr.static_property_name() { - if matches!(ident, "log" | "debug" | "info" | "warn" | "error") { - let call_expr_arg_len = call_expr.arguments.len(); + for (i, arg) in call_expr.arguments.iter().enumerate() { + if let Argument::Expression(expression_arg) = &arg { + let (literal_raw, is_template_lit) = match expression_arg { + Expression::StringLiteral(string_lit) => { + let literal_raw = string_lit.value.as_str(); - for (i, arg) in call_expr.arguments.iter().enumerate() { - if let Argument::Expression(expression_arg) = &arg { - let (literal_raw, is_template_lit) = match expression_arg { - Expression::StringLiteral(string_lit) => { - let literal_raw = string_lit.value.as_str(); - - (literal_raw, false) - } - Expression::TemplateLiteral(string_lit) => { - let literal_raw = string_lit - .span - .source_text(ctx.source_text().as_ref()) - .trim_start_matches('`') - .trim_end_matches('`'); - - (literal_raw, true) - } - - _ => continue, - }; - - if check_literal_leading(i, literal_raw) { - report_diagnostic( - "leading", - ident, - expression_arg.span(), - literal_raw, - is_template_lit, - ctx, - ); - } - - if check_literal_trailing(i, literal_raw, call_expr_arg_len) { - report_diagnostic( - "trailing", - ident, - expression_arg.span(), - literal_raw, - is_template_lit, - ctx, - ); - } + (literal_raw, false) } + Expression::TemplateLiteral(string_lit) => { + let literal_raw = string_lit + .span + .source_text(ctx.source_text().as_ref()) + .trim_start_matches('`') + .trim_end_matches('`'); + + (literal_raw, true) + } + + _ => continue, + }; + + if check_literal_leading(i, literal_raw) { + report_diagnostic( + "leading", + // SAFETY: `is_method_call` ensures that `call_expr`'s `callee` is a `MemberExpression` with a `MemberExpression` as its `object`. + call_expr_method_callee_info(call_expr).unwrap().1, + expression_arg.span(), + literal_raw, + is_template_lit, + ctx, + ); + } + + if check_literal_trailing(i, literal_raw, call_expr_arg_len) { + report_diagnostic( + "trailing", + // SAFETY: `is_method_call` ensures that `call_expr`'s `callee` is a `MemberExpression` with a `MemberExpression` as its `object`. + call_expr_method_callee_info(call_expr).unwrap().1, + expression_arg.span(), + literal_raw, + is_template_lit, + ctx, + ); } } } diff --git a/crates/oxc_linter/src/rules/unicorn/prefer_array_flat_map.rs b/crates/oxc_linter/src/rules/unicorn/prefer_array_flat_map.rs index c90cbe28d..cc40aa8e1 100644 --- a/crates/oxc_linter/src/rules/unicorn/prefer_array_flat_map.rs +++ b/crates/oxc_linter/src/rules/unicorn/prefer_array_flat_map.rs @@ -46,7 +46,7 @@ impl Rule for PreferArrayFlatMap { return; } - if !is_method_call(flat_call_expr, Some(&["flat"]), None, None) { + if !is_method_call(flat_call_expr, None, Some(&["flat"]), None, None) { return; } let Expression::MemberExpression(member_expr) = &flat_call_expr.callee else { return }; @@ -54,7 +54,7 @@ impl Rule for PreferArrayFlatMap { else { return; }; - if !is_method_call(call_expr, Some(&["map"]), None, None) { + if !is_method_call(call_expr, None, Some(&["map"]), None, None) { return; } diff --git a/crates/oxc_linter/src/rules/unicorn/prefer_array_some.rs b/crates/oxc_linter/src/rules/unicorn/prefer_array_some.rs index cb64bb314..4fbf80d66 100644 --- a/crates/oxc_linter/src/rules/unicorn/prefer_array_some.rs +++ b/crates/oxc_linter/src/rules/unicorn/prefer_array_some.rs @@ -55,7 +55,7 @@ impl Rule for PreferArraySome { fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { match node.kind() { AstKind::CallExpression(call_expr) => { - if !is_method_call(call_expr, Some(&["find", "findLast"]), Some(1), Some(2)) { + if !is_method_call(call_expr, None, Some(&["find", "findLast"]), Some(1), Some(2)) { return; } @@ -103,7 +103,7 @@ impl Rule for PreferArraySome { return; }; - if !is_method_call(left_call_expr, Some(&["filter"]), None, None) { + if !is_method_call(left_call_expr, None, Some(&["filter"]), None, None) { return; }