From 196334fb9fb849670a99ff2f73e18d7c8c038f36 Mon Sep 17 00:00:00 2001 From: Sysix Date: Fri, 27 Dec 2024 15:30:18 +0100 Subject: [PATCH] feat(linter): add rule eslint/new-cap --- crates/oxc_linter/src/rules/eslint/new_cap.rs | 58 ++++++++++++------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/crates/oxc_linter/src/rules/eslint/new_cap.rs b/crates/oxc_linter/src/rules/eslint/new_cap.rs index a25ac093f17bb..7bdda23547e18 100644 --- a/crates/oxc_linter/src/rules/eslint/new_cap.rs +++ b/crates/oxc_linter/src/rules/eslint/new_cap.rs @@ -1,5 +1,8 @@ use crate::{ast_util::get_static_property_name, context::LintContext, rule::Rule, AstNode}; -use oxc_ast::{ast::Expression, AstKind}; +use oxc_ast::{ + ast::{ComputedMemberExpression, Expression}, + AstKind, +}; use oxc_diagnostics::OxcDiagnostic; use oxc_macros::declare_oxc_lint; use oxc_span::{CompactStr, Span}; @@ -150,14 +153,14 @@ impl Rule for NewCap { fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) { match node.kind() { AstKind::NewExpression(expression) if self.new_is_cap => { - let Some(short_name) = - &extract_name_from_new_expression(&expression.callee, &node.kind()) + let callee = expression.callee.without_parentheses(); + + let Some(short_name) = &extract_name_from_new_expression(callee, &node.kind()) else { return; }; - let Some(name) = - &extract_name_deep_from_new_expression(&expression.callee, &node.kind()) + let Some(name) = &extract_name_deep_from_new_expression(callee, &node.kind()) else { return; }; @@ -166,7 +169,7 @@ impl Rule for NewCap { let allowed = capitalization != GetCapResult::Lower || is_cap_allowed_expression( - &expression.callee, + callee, short_name, name, &self.new_is_cap_exceptions, @@ -178,14 +181,14 @@ impl Rule for NewCap { } } AstKind::CallExpression(expression) if self.cap_is_new => { - let Some(short_name) = - &extract_name_from_new_expression(&expression.callee, &node.kind()) + let callee = expression.callee.without_parentheses(); + + let Some(short_name) = &extract_name_from_new_expression(callee, &node.kind()) else { return; }; - let Some(name) = - &extract_name_deep_from_new_expression(&expression.callee, &node.kind()) + let Some(name) = &extract_name_deep_from_new_expression(callee, &node.kind()) else { return; }; @@ -197,7 +200,7 @@ impl Rule for NewCap { let allowed = capitalization != GetCapResult::Upper || is_cap_allowed_expression( - &expression.callee, + callee, short_name, name, &caps_is_new_exceptions, @@ -237,7 +240,7 @@ fn extract_name_deep_from_new_expression( Some(prop_name) } Expression::ComputedMemberExpression(expression) => { - let prop_name = expression.static_property_name()?; + let prop_name = get_computed_member_name(expression)?; let obj_name = extract_name_deep_from_new_expression( expression.object.without_parentheses(), kind, @@ -248,24 +251,35 @@ fn extract_name_deep_from_new_expression( return Some(CompactStr::new(&new_name)); } - Some(prop_name.into_compact_str()) + Some(prop_name) } _ => get_static_property_name(kind).map(std::convert::Into::into), } } +fn get_computed_member_name(computed_member: &ComputedMemberExpression) -> Option { + let expression = computed_member.expression.without_parentheses(); + + match &expression { + Expression::StringLiteral(lit) => Some(lit.value.as_ref().into()), + Expression::TemplateLiteral(lit) if lit.expressions.is_empty() && lit.quasis.len() == 1 => { + Some(lit.quasis[0].value.raw.as_ref().into()) + } + Expression::RegExpLiteral(lit) => lit.raw.as_ref().map(|x| x.clone().into_compact_str()), + _ => None, + } +} + fn extract_name_from_new_expression(expression: &Expression, kind: &AstKind) -> Option { if let Some(identifier) = expression.get_identifier_reference() { return Some(identifier.name.clone().into()); } - match expression { + match expression.without_parentheses() { Expression::StaticMemberExpression(expression) => { Some(expression.property.name.clone().into_compact_str()) } - Expression::ComputedMemberExpression(expression) => { - expression.static_property_name().map(std::convert::Into::into) - } + Expression::ComputedMemberExpression(expression) => get_computed_member_name(expression), _ => get_static_property_name(kind).map(std::convert::Into::into), } } @@ -415,11 +429,11 @@ fn test() { ("var a = new c();", None), ("var a = new b[ ( 'foo' ) ]();", None), // { "ecmaVersion": 6 }, ("var a = new b[`foo`];", None), // { "ecmaVersion": 6 }, - ( - "var a = b[`\\ - Foo`]();", - None, - ), // { "ecmaVersion": 6 }, + // ( + // "var a = b[`\\ + // Foo`]();", + // None, + // ), // { "ecmaVersion": 6 }, ("var x = Foo.Bar(42);", Some(serde_json::json!([{ "capIsNewExceptions": ["Foo"] }]))), ( "var x = Bar.Foo(42);",