diff --git a/crates/oxc_ast/src/ast_impl/js.rs b/crates/oxc_ast/src/ast_impl/js.rs index 7927e5016561c..fa243d2d5adb9 100644 --- a/crates/oxc_ast/src/ast_impl/js.rs +++ b/crates/oxc_ast/src/ast_impl/js.rs @@ -544,12 +544,12 @@ impl<'a> TemplateLiteral<'a> { /// - `` `foo` `` => `true` /// - `` `foo${bar}qux` `` => `false` pub fn is_no_substitution_template(&self) -> bool { - self.expressions.is_empty() && self.quasis.len() == 1 + self.quasis.len() == 1 } /// Get single quasi from `template` pub fn quasi(&self) -> Option> { - self.quasis.first().and_then(|quasi| quasi.value.cooked) + if self.is_no_substitution_template() { self.quasis[0].value.cooked } else { None } } } diff --git a/crates/oxc_ecmascript/src/side_effects/may_have_side_effects.rs b/crates/oxc_ecmascript/src/side_effects/may_have_side_effects.rs index 63ef95e7d3d3d..5ad8035eced6b 100644 --- a/crates/oxc_ecmascript/src/side_effects/may_have_side_effects.rs +++ b/crates/oxc_ecmascript/src/side_effects/may_have_side_effects.rs @@ -417,13 +417,9 @@ impl<'a> MayHaveSideEffects<'a> for ComputedMemberExpression<'a> { Expression::StringLiteral(s) => { property_access_may_have_side_effects(&self.object, &s.value, ctx) } - Expression::TemplateLiteral(t) if t.is_no_substitution_template() => { - property_access_may_have_side_effects( - &self.object, - &t.quasi().expect("template literal must have at least one quasi"), - ctx, - ) - } + Expression::TemplateLiteral(t) => t.quasi().is_some_and(|quasi| { + property_access_may_have_side_effects(&self.object, &quasi, ctx) + }), Expression::NumericLiteral(n) => !n.value.to_integer_index().is_some_and(|n| { !integer_index_property_access_may_have_side_effects(&self.object, n, ctx) }), diff --git a/crates/oxc_ecmascript/src/to_primitive.rs b/crates/oxc_ecmascript/src/to_primitive.rs index f96f7068c7a69..94cab7aa16815 100644 --- a/crates/oxc_ecmascript/src/to_primitive.rs +++ b/crates/oxc_ecmascript/src/to_primitive.rs @@ -93,10 +93,7 @@ pub fn maybe_object_with_to_primitive_related_properties_overridden( matches!(str.value.as_str(), "toString" | "valueOf") } PropertyKey::TemplateLiteral(temp) => { - !temp.is_no_substitution_template() - || temp - .quasi() - .is_some_and(|val| matches!(val.as_str(), "toString" | "valueOf")) + temp.quasi().is_some_and(|val| matches!(val.as_str(), "toString" | "valueOf")) } _ => true, }, diff --git a/crates/oxc_linter/src/ast_util.rs b/crates/oxc_linter/src/ast_util.rs index 5605a92427f89..5bb14de33eb5b 100644 --- a/crates/oxc_linter/src/ast_util.rs +++ b/crates/oxc_linter/src/ast_util.rs @@ -308,9 +308,7 @@ pub fn extract_regex_flags<'a>( } let flag_arg = match &args[1] { Argument::StringLiteral(flag_arg) => flag_arg.value, - Argument::TemplateLiteral(template) if template.is_no_substitution_template() => { - template.quasi().expect("no-substitution templates always have a quasi") - } + Argument::TemplateLiteral(template) => template.quasi()?, _ => return None, }; let mut flags = RegExpFlags::empty(); diff --git a/crates/oxc_linter/src/rules/eslint/valid_typeof.rs b/crates/oxc_linter/src/rules/eslint/valid_typeof.rs index 44ceaa8d4f718..ecf1c8c347dc8 100644 --- a/crates/oxc_linter/src/rules/eslint/valid_typeof.rs +++ b/crates/oxc_linter/src/rules/eslint/valid_typeof.rs @@ -124,8 +124,8 @@ impl Rule for ValidTypeof { } if let Expression::TemplateLiteral(template) = sibling { - if template.expressions.is_empty() { - if template.quasi().is_some_and(|value| !VALID_TYPES.contains(&value.as_str())) { + if let Some(quasi) = template.quasi() { + if !VALID_TYPES.contains(&quasi.as_str()) { ctx.diagnostic(invalid_value(None, sibling.span())); } return; diff --git a/crates/oxc_linter/src/rules/jest/valid_title.rs b/crates/oxc_linter/src/rules/jest/valid_title.rs index 5588ca55ae863..a145e2420fb51 100644 --- a/crates/oxc_linter/src/rules/jest/valid_title.rs +++ b/crates/oxc_linter/src/rules/jest/valid_title.rs @@ -180,9 +180,6 @@ impl ValidTitle { ); } Argument::TemplateLiteral(template_literal) => { - if !template_literal.is_no_substitution_template() { - return; - } if let Some(quasi) = template_literal.quasi() { validate_title( quasi.as_str(), diff --git a/crates/oxc_linter/src/rules/react/button_has_type.rs b/crates/oxc_linter/src/rules/react/button_has_type.rs index 94852aa538e6d..e8b9616186ae1 100644 --- a/crates/oxc_linter/src/rules/react/button_has_type.rs +++ b/crates/oxc_linter/src/rules/react/button_has_type.rs @@ -180,15 +180,9 @@ impl ButtonHasType { Expression::StringLiteral(str) => { self.is_valid_button_type_prop_string_literal(str.value.as_str()) } - Expression::TemplateLiteral(template_literal) => { - if !template_literal.is_no_substitution_template() { - return false; - } - if let Some(quasi) = template_literal.quasi() { - return self.is_valid_button_type_prop_string_literal(quasi.as_str()); - } - false - } + Expression::TemplateLiteral(template_literal) => template_literal + .quasi() + .is_some_and(|quasi| self.is_valid_button_type_prop_string_literal(quasi.as_str())), Expression::ConditionalExpression(conditional_expr) => { self.is_valid_button_type_prop_expression(&conditional_expr.consequent) && self.is_valid_button_type_prop_expression(&conditional_expr.alternate) diff --git a/crates/oxc_linter/src/rules/react/jsx_curly_brace_presence.rs b/crates/oxc_linter/src/rules/react/jsx_curly_brace_presence.rs index a9af3c8ecbfc7..a658f3c9a465a 100644 --- a/crates/oxc_linter/src/rules/react/jsx_curly_brace_presence.rs +++ b/crates/oxc_linter/src/rules/react/jsx_curly_brace_presence.rs @@ -462,8 +462,9 @@ impl JsxCurlyBracePresence { } } Expression::TemplateLiteral(template) => { - if allowed.is_never() && template.is_no_substitution_template() { - let string = template.quasi().unwrap(); + if allowed.is_never() + && let Some(string) = template.quasi() + { if contains_quote_characters(string.as_str()) || is_allowed_string_like( ctx, diff --git a/crates/oxc_linter/src/utils/express.rs b/crates/oxc_linter/src/utils/express.rs index 0b5f08dab89cd..5b2162cea5276 100644 --- a/crates/oxc_linter/src/utils/express.rs +++ b/crates/oxc_linter/src/utils/express.rs @@ -34,8 +34,8 @@ pub fn as_endpoint_registration<'a, 'n>( Expression::StringLiteral(path) => { Some((Some(path.value), &call.arguments.as_slice()[1..])) } - Expression::TemplateLiteral(template) if template.is_no_substitution_template() => { - Some((template.quasi(), &call.arguments.as_slice()[1..])) + Expression::TemplateLiteral(template) => { + template.quasi().map(|quasi| (Some(quasi), &call.arguments.as_slice()[1..])) } _ => Some((None, call.arguments.as_slice())), } diff --git a/crates/oxc_linter/src/utils/jest.rs b/crates/oxc_linter/src/utils/jest.rs index be68f32a0877a..486f26a45fcad 100644 --- a/crates/oxc_linter/src/utils/jest.rs +++ b/crates/oxc_linter/src/utils/jest.rs @@ -3,7 +3,7 @@ use std::borrow::Cow; use oxc_ast::{ AstKind, ast::{ - CallExpression, Expression, ImportDeclaration, ImportDeclarationSpecifier, TemplateLiteral, + CallExpression, Expression, ImportDeclaration, ImportDeclarationSpecifier, match_member_expression, }, }; @@ -271,8 +271,10 @@ pub fn get_node_name_vec<'a>(expr: &'a Expression<'a>) -> Vec> { Expression::StringLiteral(string_literal) => { chain.push(Cow::Borrowed(&string_literal.value)); } - Expression::TemplateLiteral(template_literal) if is_pure_string(template_literal) => { - chain.push(Cow::Borrowed(template_literal.quasi().unwrap().as_str())); + Expression::TemplateLiteral(template_literal) => { + if let Some(quasi) = template_literal.quasi() { + chain.push(Cow::Borrowed(quasi.as_str())); + } } Expression::TaggedTemplateExpression(tagged_expr) => { chain.extend(get_node_name_vec(&tagged_expr.tag)); @@ -294,10 +296,6 @@ pub fn get_node_name_vec<'a>(expr: &'a Expression<'a>) -> Vec> { chain } -fn is_pure_string(template_literal: &TemplateLiteral) -> bool { - template_literal.expressions.is_empty() && template_literal.quasis.len() == 1 -} - pub fn is_equality_matcher(matcher: &KnownMemberExpressionProperty) -> bool { matcher.is_name_equal("toBe") || matcher.is_name_equal("toEqual") diff --git a/crates/oxc_linter/src/utils/jest/parse_jest_fn.rs b/crates/oxc_linter/src/utils/jest/parse_jest_fn.rs index 882766cc128f2..b19b65b9322bc 100644 --- a/crates/oxc_linter/src/utils/jest/parse_jest_fn.rs +++ b/crates/oxc_linter/src/utils/jest/parse_jest_fn.rs @@ -13,7 +13,7 @@ use oxc_span::Span; use crate::{ context::LintContext, - utils::jest::{JestFnKind, JestGeneralFnKind, PossibleJestNode, is_pure_string}, + utils::jest::{JestFnKind, JestGeneralFnKind, PossibleJestNode}, utils::valid_vitest_fn::is_valid_vitest_call, }; @@ -554,7 +554,9 @@ fn recurse_extend_node_chain<'a>( span: string_literal.span, }); } - Expression::TemplateLiteral(template_literal) if is_pure_string(template_literal) => { + Expression::TemplateLiteral(template_literal) + if template_literal.is_no_substitution_template() => + { chain.push(KnownMemberExpressionProperty { element: MemberExpressionElement::Expression(expr), parent: *parent, diff --git a/crates/oxc_linter/src/utils/unicorn.rs b/crates/oxc_linter/src/utils/unicorn.rs index 6a3587c72decb..35e48d30276bd 100644 --- a/crates/oxc_linter/src/utils/unicorn.rs +++ b/crates/oxc_linter/src/utils/unicorn.rs @@ -181,8 +181,7 @@ pub fn is_same_expression(left: &Expression, right: &Expression, ctx: &LintConte } (Expression::StringLiteral(string_lit), Expression::TemplateLiteral(template_lit)) | (Expression::TemplateLiteral(template_lit), Expression::StringLiteral(string_lit)) => { - return template_lit.is_no_substitution_template() - && string_lit.value == template_lit.quasi().unwrap(); + return template_lit.quasi().is_some_and(|val| val.as_str() == string_lit.value); } (Expression::TemplateLiteral(left_str), Expression::TemplateLiteral(right_str)) => { return left_str.quasis.content_eq(&right_str.quasis) @@ -304,9 +303,7 @@ pub fn is_same_member_expression( // ex) x[/regex/] === x[`/regex/`] (Expression::TemplateLiteral(template_lit), Expression::RegExpLiteral(regex_lit)) | (Expression::RegExpLiteral(regex_lit), Expression::TemplateLiteral(template_lit)) => { - if !(template_lit.is_no_substitution_template() - && template_lit.quasi().unwrap() == regex_lit.raw.as_ref().unwrap()) - { + if !template_lit.quasi().is_some_and(|val| val == regex_lit.raw.as_ref().unwrap()) { return false; } }