diff --git a/crates/biome_css_analyze/src/lint/a11y/use_generic_font_names.rs b/crates/biome_css_analyze/src/lint/a11y/use_generic_font_names.rs index 59502bb81616..63043dc495e6 100644 --- a/crates/biome_css_analyze/src/lint/a11y/use_generic_font_names.rs +++ b/crates/biome_css_analyze/src/lint/a11y/use_generic_font_names.rs @@ -158,6 +158,7 @@ impl Rule for UseGenericFontNames { fn is_in_font_face_at_rule(node: &CssGenericProperty) -> bool { node.syntax() .ancestors() + .skip(1) .find(|n| n.kind() == CssSyntaxKind::CSS_AT_RULE) .and_then(|n| n.cast::()) .and_then(|n| n.rule().ok()) diff --git a/crates/biome_css_analyze/src/lint/correctness/no_unknown_unit.rs b/crates/biome_css_analyze/src/lint/correctness/no_unknown_unit.rs index 738a79c731dd..d35d563b3921 100644 --- a/crates/biome_css_analyze/src/lint/correctness/no_unknown_unit.rs +++ b/crates/biome_css_analyze/src/lint/correctness/no_unknown_unit.rs @@ -111,15 +111,15 @@ impl Rule for NoUnknownUnit { if unit == "x" { let mut allow_x = false; - for ancestor in dimension.unit_token().ok()?.ancestors() { + for ancestor in dimension.unit_token().ok()?.ancestors().skip(1) { match ancestor.kind() { CssSyntaxKind::CSS_FUNCTION => { let function_name_token = ancestor - .cast::()? - .name() - .ok()? - .as_css_identifier() - .and_then(|name| name.value_token().ok())?; + .cast::()? + .name() + .ok()? + .as_css_identifier() + .and_then(|name| name.value_token().ok())?; let function_name = function_name_token .text_trimmed() .to_ascii_lowercase_cow(); diff --git a/crates/biome_css_analyze/src/lint/correctness/no_unmatchable_anb_selector.rs b/crates/biome_css_analyze/src/lint/correctness/no_unmatchable_anb_selector.rs index f956aeba3e54..852e69e56d2f 100644 --- a/crates/biome_css_analyze/src/lint/correctness/no_unmatchable_anb_selector.rs +++ b/crates/biome_css_analyze/src/lint/correctness/no_unmatchable_anb_selector.rs @@ -129,6 +129,7 @@ fn is_within_not_pseudo_class(node: &AnyCssPseudoClassNth) -> bool { let number_of_not = node .syntax() .ancestors() + .skip(1) .filter_map(|n| n.cast::()) .filter_map(|n| n.name().ok()) .filter_map(|n| n.value_token().ok()) diff --git a/crates/biome_css_analyze/src/lint/suspicious/no_duplicate_properties.rs b/crates/biome_css_analyze/src/lint/suspicious/no_duplicate_properties.rs index a8d76de01379..3aa910e5a0a9 100644 --- a/crates/biome_css_analyze/src/lint/suspicious/no_duplicate_properties.rs +++ b/crates/biome_css_analyze/src/lint/suspicious/no_duplicate_properties.rs @@ -74,6 +74,7 @@ impl Rule for NoDuplicateProperties { if prop .syntax() .ancestors() + .skip(1) .any(|node| CssKeyframesAtRule::can_cast(node.kind())) { continue; diff --git a/crates/biome_html_analyze/src/lint/a11y/no_autofocus.rs b/crates/biome_html_analyze/src/lint/a11y/no_autofocus.rs index 4aee96a96251..d8bf50362b0d 100644 --- a/crates/biome_html_analyze/src/lint/a11y/no_autofocus.rs +++ b/crates/biome_html_analyze/src/lint/a11y/no_autofocus.rs @@ -127,7 +127,7 @@ fn is_inside_allowed_context(attr: &HtmlAttribute) -> Option { let mut skip_first_element = true; // Walk up the ancestors to find if we're inside a dialog or popover - for ancestor in attr.syntax().ancestors() { + for ancestor in attr.syntax().ancestors().skip(1) { let Some(tag_element) = get_tag_element(&ancestor) else { continue; }; diff --git a/crates/biome_html_analyze/src/lint/nursery/use_vue_valid_v_if.rs b/crates/biome_html_analyze/src/lint/nursery/use_vue_valid_v_if.rs index 1be575b749b5..ff0df51b412d 100644 --- a/crates/biome_html_analyze/src/lint/nursery/use_vue_valid_v_if.rs +++ b/crates/biome_html_analyze/src/lint/nursery/use_vue_valid_v_if.rs @@ -169,6 +169,7 @@ impl Rule for UseVueValidVIf { fn find_conflicting_else_directives(v_if: &VueDirective) -> Option { v_if.syntax() .ancestors() + .skip(1) .find_map(HtmlAttributeList::cast)? .into_iter() .find_map(|attr| { diff --git a/crates/biome_js_analyze/src/assist/source/use_sorted_attributes.rs b/crates/biome_js_analyze/src/assist/source/use_sorted_attributes.rs index 792333f04978..f81f0c984e60 100644 --- a/crates/biome_js_analyze/src/assist/source/use_sorted_attributes.rs +++ b/crates/biome_js_analyze/src/assist/source/use_sorted_attributes.rs @@ -139,7 +139,7 @@ impl Rule for UseSortedAttributes { } fn text_range(ctx: &RuleContext, _state: &Self::State) -> Option { - ctx.query().syntax().ancestors().find_map(|node| { + ctx.query().syntax().ancestors().skip(1).find_map(|node| { JsxOpeningElement::cast_ref(&node) .map(|element| element.range()) .or_else(|| JsxSelfClosingElement::cast_ref(&node).map(|element| element.range())) diff --git a/crates/biome_js_analyze/src/assist/source/use_sorted_keys.rs b/crates/biome_js_analyze/src/assist/source/use_sorted_keys.rs index 972bfd86a4c2..6d874cd19cbc 100644 --- a/crates/biome_js_analyze/src/assist/source/use_sorted_keys.rs +++ b/crates/biome_js_analyze/src/assist/source/use_sorted_keys.rs @@ -288,6 +288,7 @@ impl Rule for UseSortedKeys { ctx.query() .syntax() .ancestors() + .skip(1) .find_map(JsObjectExpression::cast) .map(|object| object.range()) } diff --git a/crates/biome_js_analyze/src/frameworks/mod.rs b/crates/biome_js_analyze/src/frameworks/mod.rs index 99dbad9bed7b..5493502a948a 100644 --- a/crates/biome_js_analyze/src/frameworks/mod.rs +++ b/crates/biome_js_analyze/src/frameworks/mod.rs @@ -55,6 +55,7 @@ pub(crate) fn is_framework_lib_export(binding: &Binding, package_names: &[&str]) binding .syntax() .ancestors() + .skip(1) .find_map(|ancestor| JsImport::cast(ancestor)?.source_text().ok()) .is_some_and(|source| package_names.contains(&source.text())) } diff --git a/crates/biome_js_analyze/src/frameworks/vue/vue_component.rs b/crates/biome_js_analyze/src/frameworks/vue/vue_component.rs index 62993f90c2a4..17176cc130c1 100644 --- a/crates/biome_js_analyze/src/frameworks/vue/vue_component.rs +++ b/crates/biome_js_analyze/src/frameworks/vue/vue_component.rs @@ -754,6 +754,7 @@ impl AnyVueSetupDeclaration { && let Some(declarator) = binding .syntax() .ancestors() + .skip(1) .find_map(|syntax| JsVariableDeclarator::try_cast(syntax).ok()) && let Some(initializer) = declarator.initializer() && let Some(expression) = initializer @@ -781,6 +782,7 @@ impl AnyVueSetupDeclaration { && let Some(declarator) = binding .syntax() .ancestors() + .skip(1) .find_map(|syntax| JsVariableDeclarator::try_cast(syntax).ok()) && let Some(initializer) = declarator.initializer() && let Some(expression) = initializer @@ -811,6 +813,7 @@ impl AnyVueSetupDeclaration { && let Some(declarator) = binding .syntax() .ancestors() + .skip(1) .find_map(|syntax| JsVariableDeclarator::try_cast(syntax).ok()) && let Some(decl_initializer) = declarator.initializer() && let Some(decl_expr) = decl_initializer diff --git a/crates/biome_js_analyze/src/lint/a11y/use_aria_activedescendant_with_tabindex.rs b/crates/biome_js_analyze/src/lint/a11y/use_aria_activedescendant_with_tabindex.rs index dc693f0f6988..e3e426b413c8 100644 --- a/crates/biome_js_analyze/src/lint/a11y/use_aria_activedescendant_with_tabindex.rs +++ b/crates/biome_js_analyze/src/lint/a11y/use_aria_activedescendant_with_tabindex.rs @@ -106,6 +106,7 @@ impl Rule for UseAriaActivedescendantWithTabindex { let old_attribute_list = descendant_attribute .syntax() .ancestors() + .skip(1) .find_map(JsxAttributeList::cast)?; let new_attribute = jsx_attribute(AnyJsxAttributeName::JsxName(jsx_name( diff --git a/crates/biome_js_analyze/src/lint/complexity/no_this_in_static.rs b/crates/biome_js_analyze/src/lint/complexity/no_this_in_static.rs index c938704ee4d3..b1f0d54551a0 100644 --- a/crates/biome_js_analyze/src/lint/complexity/no_this_in_static.rs +++ b/crates/biome_js_analyze/src/lint/complexity/no_this_in_static.rs @@ -100,6 +100,7 @@ impl Rule for NoThisInStatic { let static_method = this_super_expression .syntax() .ancestors() + .skip(1) .find(|x| { AnyJsControlFlowRoot::can_cast(x.kind()) && !JsArrowFunctionExpression::can_cast(x.kind()) diff --git a/crates/biome_js_analyze/src/lint/complexity/no_useless_constructor.rs b/crates/biome_js_analyze/src/lint/complexity/no_useless_constructor.rs index 7a61593205fa..d77abc007284 100644 --- a/crates/biome_js_analyze/src/lint/complexity/no_useless_constructor.rs +++ b/crates/biome_js_analyze/src/lint/complexity/no_useless_constructor.rs @@ -164,7 +164,11 @@ impl Rule for NoUselessConstructor { return None; } } - let class = constructor.syntax().ancestors().find_map(AnyJsClass::cast); + let class = constructor + .syntax() + .ancestors() + .skip(1) + .find_map(AnyJsClass::cast); if let Some(class) = &class && !class.decorators().is_empty() { diff --git a/crates/biome_js_analyze/src/lint/complexity/no_useless_label.rs b/crates/biome_js_analyze/src/lint/complexity/no_useless_label.rs index aa242b0cb00d..666017bd58df 100644 --- a/crates/biome_js_analyze/src/lint/complexity/no_useless_label.rs +++ b/crates/biome_js_analyze/src/lint/complexity/no_useless_label.rs @@ -58,7 +58,7 @@ impl Rule for NoUselessLabel { _ => None, }?; let label = label_token.text_trimmed(); - for parent in stmt.syntax().ancestors() { + for parent in stmt.syntax().ancestors().skip(1) { if is_breakable_statement_kind(parent.kind()) { if let Some(labeled_stmt) = JsLabeledStatement::cast(parent.parent()?) && labeled_stmt.label_token().ok()?.text_trimmed() == label diff --git a/crates/biome_js_analyze/src/lint/complexity/no_useless_this_alias.rs b/crates/biome_js_analyze/src/lint/complexity/no_useless_this_alias.rs index 5a55427ef86e..bb50eb97db7d 100644 --- a/crates/biome_js_analyze/src/lint/complexity/no_useless_this_alias.rs +++ b/crates/biome_js_analyze/src/lint/complexity/no_useless_this_alias.rs @@ -89,6 +89,7 @@ impl Rule for NoUselessThisAlias { let this_scope = declarator .syntax() .ancestors() + .skip(1) .find_map(AnyJsControlFlowRoot::cast)?; for write in id.all_writes(model) { let assign = JsAssignmentExpression::cast(write.syntax().parent()?)?; @@ -106,6 +107,7 @@ impl Rule for NoUselessThisAlias { let current_this_scope = reference .syntax() .ancestors() + .skip(1) .filter(|x| !JsArrowFunctionExpression::can_cast(x.kind())) .find_map(AnyJsControlFlowRoot::cast)?; if this_scope != current_this_scope { @@ -138,6 +140,7 @@ impl Rule for NoUselessThisAlias { let var_decl = declarator .syntax() .ancestors() + .skip(1) .find_map(JsVariableDeclaration::cast)?; let mut mutation = ctx.root().begin(); let this_expr = AnyJsExpression::from(make::js_this_expression(make::token(T![this]))); diff --git a/crates/biome_js_analyze/src/lint/correctness/no_constant_condition.rs b/crates/biome_js_analyze/src/lint/correctness/no_constant_condition.rs index 99792fde3059..8b6bb3cea86b 100644 --- a/crates/biome_js_analyze/src/lint/correctness/no_constant_condition.rs +++ b/crates/biome_js_analyze/src/lint/correctness/no_constant_condition.rs @@ -160,7 +160,7 @@ impl ConditionalStatement { } // Checks if the self statement is in a generator function fn is_in_generator_function(&self) -> bool { - self.syntax().ancestors().any(|node| { + self.syntax().ancestors().skip(1).any(|node| { match JsFunctionDeclaration::try_cast(node) { Ok(func_decl) => func_decl.star_token(), Err(node) => { diff --git a/crates/biome_js_analyze/src/lint/correctness/no_constructor_return.rs b/crates/biome_js_analyze/src/lint/correctness/no_constructor_return.rs index 8645c2e4dec8..82650543f115 100644 --- a/crates/biome_js_analyze/src/lint/correctness/no_constructor_return.rs +++ b/crates/biome_js_analyze/src/lint/correctness/no_constructor_return.rs @@ -76,6 +76,7 @@ impl Rule for NoConstructorReturn { let _arg = ret.argument()?; ret.syntax() .ancestors() + .skip(1) .find(|x| AnyJsControlFlowRoot::can_cast(x.kind())) .and_then(JsConstructorClassMember::cast) } diff --git a/crates/biome_js_analyze/src/lint/correctness/no_invalid_constructor_super.rs b/crates/biome_js_analyze/src/lint/correctness/no_invalid_constructor_super.rs index d57aa1da8eee..edc9308726b3 100644 --- a/crates/biome_js_analyze/src/lint/correctness/no_invalid_constructor_super.rs +++ b/crates/biome_js_analyze/src/lint/correctness/no_invalid_constructor_super.rs @@ -122,6 +122,7 @@ impl Rule for NoInvalidConstructorSuper { let extends_clause = node .syntax() .ancestors() + .skip(1) .find_map(|node| AnyJsClass::cast(node)?.extends_clause()); match (super_range, extends_clause) { diff --git a/crates/biome_js_analyze/src/lint/correctness/no_nested_component_definitions.rs b/crates/biome_js_analyze/src/lint/correctness/no_nested_component_definitions.rs index 0c427fd39296..f916fb1086e5 100644 --- a/crates/biome_js_analyze/src/lint/correctness/no_nested_component_definitions.rs +++ b/crates/biome_js_analyze/src/lint/correctness/no_nested_component_definitions.rs @@ -112,6 +112,7 @@ impl Rule for NoNestedComponentDefinitions { && let Some(parent_component) = node .syntax() .ancestors() + .skip(1) .skip_while(|ancestor| ancestor.eq(node.syntax())) .find_map(|syntax| ReactComponentInfo::from_declaration(&syntax)) { diff --git a/crates/biome_js_analyze/src/lint/correctness/no_process_global.rs b/crates/biome_js_analyze/src/lint/correctness/no_process_global.rs index 897029936ae1..f29306faa08c 100644 --- a/crates/biome_js_analyze/src/lint/correctness/no_process_global.rs +++ b/crates/biome_js_analyze/src/lint/correctness/no_process_global.rs @@ -96,6 +96,7 @@ impl Rule for NoProcessGlobal { .query() .syntax() .ancestors() + .skip(1) .find(is_top_level_statement)?; // insert new import at: // 1. after the most recent import statement. Or, if no such import exist diff --git a/crates/biome_js_analyze/src/lint/correctness/no_setter_return.rs b/crates/biome_js_analyze/src/lint/correctness/no_setter_return.rs index ad6e819a07a6..2db7169b9125 100644 --- a/crates/biome_js_analyze/src/lint/correctness/no_setter_return.rs +++ b/crates/biome_js_analyze/src/lint/correctness/no_setter_return.rs @@ -92,6 +92,7 @@ impl Rule for NoSetterReturn { let _arg = ret.argument()?; ret.syntax() .ancestors() + .skip(1) .find(|x| AnyJsControlFlowRoot::can_cast(x.kind())) .and_then(JsSetterMember::cast) } diff --git a/crates/biome_js_analyze/src/lint/correctness/no_solid_destructured_props.rs b/crates/biome_js_analyze/src/lint/correctness/no_solid_destructured_props.rs index 98e6693a416d..bbcdc171f70e 100644 --- a/crates/biome_js_analyze/src/lint/correctness/no_solid_destructured_props.rs +++ b/crates/biome_js_analyze/src/lint/correctness/no_solid_destructured_props.rs @@ -89,6 +89,7 @@ impl Rule for NoSolidDestructuredProps { let Some(parameters) = binding_pattern .syntax() .ancestors() + .skip(1) .find_map(JsParameters::cast) else { return vec![]; @@ -186,6 +187,7 @@ fn is_binding_a_jsx_prop(binding: &AnyJsBinding, model: &SemanticModel) -> Optio if reference .syntax() .ancestors() + .skip(1) .find_map(JsxExpressionAttributeValue::cast) .is_some() { diff --git a/crates/biome_js_analyze/src/lint/correctness/no_undeclared_variables.rs b/crates/biome_js_analyze/src/lint/correctness/no_undeclared_variables.rs index 50bddf0d8629..f83f9f1ee903 100644 --- a/crates/biome_js_analyze/src/lint/correctness/no_undeclared_variables.rs +++ b/crates/biome_js_analyze/src/lint/correctness/no_undeclared_variables.rs @@ -102,7 +102,7 @@ impl Rule for NoUndeclaredVariables { // arguments object within non-arrow functions if text == "arguments" { let is_in_non_arrow_function = - identifier.syntax().ancestors().any(|ancestor| { + identifier.syntax().ancestors().skip(1).any(|ancestor| { !matches!( AnyJsFunction::cast(ancestor), None | Some(AnyJsFunction::JsArrowFunctionExpression(_)) diff --git a/crates/biome_js_analyze/src/lint/correctness/use_qwik_valid_lexical_scope.rs b/crates/biome_js_analyze/src/lint/correctness/use_qwik_valid_lexical_scope.rs index e6feeff55805..c5042149fdbb 100644 --- a/crates/biome_js_analyze/src/lint/correctness/use_qwik_valid_lexical_scope.rs +++ b/crates/biome_js_analyze/src/lint/correctness/use_qwik_valid_lexical_scope.rs @@ -95,6 +95,7 @@ impl Rule for UseQwikValidLexicalScope { fn is_wrapped_with_dollar(expr: &AnyJsExpression) -> bool { expr.syntax() .ancestors() + .skip(1) .find_map(JsCallExpression::cast) .and_then(|call| call.callee().ok()) .and_then(|callee| callee.as_js_reference_identifier()) diff --git a/crates/biome_js_analyze/src/lint/nursery/no_shadow.rs b/crates/biome_js_analyze/src/lint/nursery/no_shadow.rs index f8adc868a8b6..a77051690d6e 100644 --- a/crates/biome_js_analyze/src/lint/nursery/no_shadow.rs +++ b/crates/biome_js_analyze/src/lint/nursery/no_shadow.rs @@ -249,6 +249,7 @@ fn is_inside_type_parameter(binding: &Binding) -> bool { binding .syntax() .ancestors() + .skip(1) .any(|ancestor| ancestor.cast::().is_some()) } @@ -256,6 +257,7 @@ fn is_inside_type_member(binding: &Binding) -> bool { binding .syntax() .ancestors() + .skip(1) .any(|ancestor| ancestor.cast::().is_some()) } @@ -263,5 +265,6 @@ fn is_inside_function_parameters(binding: &Binding) -> bool { binding .syntax() .ancestors() + .skip(1) .any(|ancestor| ancestor.cast::().is_some()) } diff --git a/crates/biome_js_analyze/src/lint/nursery/no_unnecessary_conditions.rs b/crates/biome_js_analyze/src/lint/nursery/no_unnecessary_conditions.rs index 1ab220eadf63..04e6efba0c48 100644 --- a/crates/biome_js_analyze/src/lint/nursery/no_unnecessary_conditions.rs +++ b/crates/biome_js_analyze/src/lint/nursery/no_unnecessary_conditions.rs @@ -313,6 +313,7 @@ fn check_condition_necessity( let inside_catch = expr .syntax() .ancestors() + .skip(1) .any(|ancestor| JsCatchClause::can_cast(ancestor.kind())); if inside_catch { diff --git a/crates/biome_js_analyze/src/lint/nursery/no_vue_ref_as_operand.rs b/crates/biome_js_analyze/src/lint/nursery/no_vue_ref_as_operand.rs index 1de2eb1cb768..5ec40aab79dd 100644 --- a/crates/biome_js_analyze/src/lint/nursery/no_vue_ref_as_operand.rs +++ b/crates/biome_js_analyze/src/lint/nursery/no_vue_ref_as_operand.rs @@ -1,12 +1,17 @@ use biome_analyze::{ - Rule, RuleDiagnostic, RuleDomain, RuleSource, context::RuleContext, declare_lint_rule + Rule, RuleDiagnostic, RuleDomain, RuleSource, context::RuleContext, declare_lint_rule, }; use biome_console::markup; use biome_diagnostics::Severity; use biome_js_semantic::SemanticModel; -use biome_js_syntax::{AnyJsExpression, AnyJsName, JsCallArgumentList, JsCallExpression, JsConditionalExpression, JsIdentifierAssignment, JsIdentifierBinding, JsIdentifierExpression, JsLogicalExpression, JsMethodObjectMember, JsStaticMemberAssignment, JsStaticMemberExpression, JsSyntaxKind, JsTemplateElement, JsTemplateExpression, JsVariableDeclaration, JsVariableDeclarator}; use biome_js_syntax::binding_ext::AnyJsIdentifierBinding; -use biome_rowan::{AstNode, SyntaxNodeCast, TextRange, declare_node_union}; +use biome_js_syntax::{ + AnyJsExpression, AnyJsName, JsCallArgumentList, JsCallExpression, JsConditionalExpression, + JsIdentifierAssignment, JsIdentifierBinding, JsIdentifierExpression, JsLogicalExpression, + JsMethodObjectMember, JsStaticMemberAssignment, JsStaticMemberExpression, JsSyntaxKind, + JsTemplateElement, JsTemplateExpression, JsVariableDeclaration, JsVariableDeclarator, +}; +use biome_rowan::{AstNode, SyntaxNodeCast, TextRange, declare_node_union}; use biome_rule_options::no_vue_ref_as_operand::NoVueRefAsOperandOptions; use crate::frameworks::vue::vue_call::is_vue_compiler_macro_call; @@ -14,39 +19,39 @@ use crate::{frameworks::vue::vue_call::is_vue_api_reference, services::semantic: declare_lint_rule! { /// Disallow the use of value wrapped by `ref()`(Composition API) as operand - /// + /// /// To access value wrapped by `ref()`, you must use `.value`. /// /// ## Examples /// /// ### Invalid - /// + /// /// ```js,expect_diagnostic /// import { ref } from "vue" - /// + /// /// const count = ref(0) /// count++ /// ``` - /// + /// /// ```js,expect_diagnostic /// import { ref } from "vue" - /// + /// /// const ok = ref(false) /// const msg = ok ? "yes" : "no" /// ``` - /// + /// /// ```js,expect_diagnostic /// import { ref } from "vue" - /// + /// /// const ok = ref(false) /// if (ok) { /// // /// } /// ``` - /// + /// /// ```js,expect_diagnostic /// import { ref } from "vue" - /// + /// /// export default { /// setup(_props, { emit }) { /// const count = ref(0) @@ -56,27 +61,27 @@ declare_lint_rule! { /// ``` /// /// ### Valid - /// + /// /// ```js /// import { ref } from "vue" - /// + /// /// const count = ref(0) /// count.value++ /// ``` - /// + /// /// ```js /// import { ref } from "vue" - /// + /// /// const ok = ref(true) /// const msg = ok.value ? "yes" : "no" /// if (ok.value) { /// // /// } /// ``` - /// + /// /// ```js /// import { ref } from "vue" - /// + /// /// export default { /// setup(_props, { emit }) { /// const count = ref(0) @@ -84,7 +89,7 @@ declare_lint_rule! { /// } /// } /// ``` - /// + /// pub NoVueRefAsOperand { version: "2.4.5", name: "noVueRefAsOperand", @@ -136,16 +141,21 @@ fn check_expression(expr: &NoVueRefAsOperandQuery, model: &SemanticModel) -> Opt NoVueRefAsOperandQuery::JsIdentifierExpression(ident_expr) => { let reference = ident_expr.name().ok()?; let binding = model.binding(&reference)?.tree(); - let declarator = binding.syntax().ancestors().find_map(JsVariableDeclarator::cast)?; + let declarator = binding + .syntax() + .ancestors() + .skip(1) + .find_map(JsVariableDeclarator::cast)?; let init_clause = declarator.initializer()?; let init_expr = init_clause.expression().ok()?; let call_expr = init_expr.as_js_call_expression()?; - let ident_binding = if let AnyJsIdentifierBinding::JsIdentifierBinding(binding) = &binding { - binding - } else { - return None - }; + let ident_binding = + if let AnyJsIdentifierBinding::JsIdentifierBinding(binding) = &binding { + binding + } else { + return None; + }; if !is_calling_a_ref(call_expr, ident_binding, model) { return None; @@ -176,7 +186,7 @@ fn check_expression(expr: &NoVueRefAsOperandQuery, model: &SemanticModel) -> Opt } // Report only refs which are constants - if let Some(declaration) = declarator.syntax().ancestors().find_map(JsVariableDeclaration::cast) + if let Some(declaration) = declarator.syntax().ancestors().skip(1).find_map(JsVariableDeclaration::cast) && (declaration.is_const()) { return Some(ident_expr.range()) } @@ -231,15 +241,20 @@ fn check_expression(expr: &NoVueRefAsOperandQuery, model: &SemanticModel) -> Opt } NoVueRefAsOperandQuery::JsIdentifierAssignment(ident_assignment) => { let binding = model.binding(ident_assignment)?.tree(); - let declarator = binding.syntax().ancestors().find_map(JsVariableDeclarator::cast)?; + let declarator = binding + .syntax() + .ancestors() + .skip(1) + .find_map(JsVariableDeclarator::cast)?; let init_clause = declarator.initializer()?; let init_expr = init_clause.expression().ok()?; let call_expr = init_expr.as_js_call_expression()?; - let ident_binding = if let AnyJsIdentifierBinding::JsIdentifierBinding(binding) = &binding { - binding - } else { - return None - }; + let ident_binding = + if let AnyJsIdentifierBinding::JsIdentifierBinding(binding) = &binding { + binding + } else { + return None; + }; if !is_calling_a_ref(call_expr, ident_binding, model) { return None; @@ -260,22 +275,26 @@ const REF_VALUE_APIS: &[&str] = &[ "toRef", "customRef", "shallowRef", - "toRefs" + "toRefs", ]; fn is_calling_a_ref( call_expr: &JsCallExpression, - ident_binding: &JsIdentifierBinding, - model: &SemanticModel) -> bool { + ident_binding: &JsIdentifierBinding, + model: &SemanticModel, +) -> bool { if let Ok(callee) = call_expr.callee() { - if ident_binding.is_under_object_pattern_binding().is_some_and(|v|v) { + if ident_binding + .is_under_object_pattern_binding() + .is_some_and(|v| v) + { return is_valid_destructured_ref(&callee, call_expr, model); } - + REF_VALUE_APIS .iter() .any(|ref_name| is_vue_api_reference(&callee, model, ref_name)) - || is_vue_compiler_macro_call(call_expr, model, "defineModel") + || is_vue_compiler_macro_call(call_expr, model, "defineModel") } else { false } @@ -310,19 +329,19 @@ fn check_static_member_access( let ref_callee_name = ref_callee_expr.get_callee_member_name()?; if ref_callee_name.text() == "toRefs" { if is_valid_static_member_wrapped_in_to_refs(ident_binding, &member) { - return None + return None; } - return Some(static_member_expr.range()) + return Some(static_member_expr.range()); } if !is_value_static_member(&member) { - return Some(ident_expr.range()) + return Some(ident_expr.range()); } None } -/// Check if a static member is `.value` +/// Check if a static member is `.value` fn is_value_static_member(member: &AnyJsName) -> bool { member .as_js_name() @@ -337,7 +356,7 @@ fn is_valid_static_member_wrapped_in_to_refs( ) -> bool { // Destructured refs: `const { foo } = toRefs(obj); foo.value` if ident_binding.is_under_pattern_binding().is_some_and(|v| v) { - return is_value_static_member(member) + return is_value_static_member(member); } // Direct refs: `const refs = toRefs(obj); refs.foo.value` @@ -380,7 +399,7 @@ fn is_emit_call_in_setup(callee_expr: &AnyJsExpression, model: &SemanticModel) - false } } - _ => false + _ => false, } } @@ -389,28 +408,23 @@ fn is_emit_in_setup_method(binding: &AnyJsIdentifierBinding) -> bool { binding .syntax() .ancestors() + .skip(1) .find_map(JsMethodObjectMember::cast) - .and_then(|method| { - method - .name() - .ok()? - .as_js_literal_member_name()? - .name() - .ok() - }) + .and_then(|method| method.name().ok()?.as_js_literal_member_name()?.name().ok()) .is_some_and(|name| name == "setup") } /// Check if emit is defined by a macro (defineEmits) fn is_emit_call_by_macro(callee: &AnyJsExpression, model: &SemanticModel) -> bool { if let Some(ident_expr) = callee.as_js_identifier_expression() - && let Ok(reference) = ident_expr.name() - && let Some(binding) = model.binding(&reference) - && let Some(parent) = binding.syntax().parent() - && let Some(decl) = parent.cast::() - && let Some(init) = decl.initializer() - && let Some(expr) = init.expression().ok() - && let Some(call_expr) = expr.as_js_call_expression() { + && let Ok(reference) = ident_expr.name() + && let Some(binding) = model.binding(&reference) + && let Some(parent) = binding.syntax().parent() + && let Some(decl) = parent.cast::() + && let Some(init) = decl.initializer() + && let Some(expr) = init.expression().ok() + && let Some(call_expr) = expr.as_js_call_expression() + { is_vue_compiler_macro_call(call_expr, model, "defineEmits") } else { false diff --git a/crates/biome_js_analyze/src/lint/performance/use_top_level_regex.rs b/crates/biome_js_analyze/src/lint/performance/use_top_level_regex.rs index 59f630775f3f..3fb194e9a1f5 100644 --- a/crates/biome_js_analyze/src/lint/performance/use_top_level_regex.rs +++ b/crates/biome_js_analyze/src/lint/performance/use_top_level_regex.rs @@ -67,30 +67,28 @@ impl Rule for UseTopLevelRegex { if flags.contains('g') || flags.contains('y') { return None; } - let found_all_allowed = - regex - .syntax() - .ancestors() - .all(|node| match AnyJsControlFlowRoot::try_cast(node) { - Ok(node) => { - matches!( - node, - AnyJsControlFlowRoot::JsStaticInitializationBlockClassMember(_) - | AnyJsControlFlowRoot::TsModuleDeclaration(_) - | AnyJsControlFlowRoot::JsModule(_) - | AnyJsControlFlowRoot::JsScript(_) - ) + let found_all_allowed = regex.syntax().ancestors().skip(1).all(|node| { + match AnyJsControlFlowRoot::try_cast(node) { + Ok(node) => { + matches!( + node, + AnyJsControlFlowRoot::JsStaticInitializationBlockClassMember(_) + | AnyJsControlFlowRoot::TsModuleDeclaration(_) + | AnyJsControlFlowRoot::JsModule(_) + | AnyJsControlFlowRoot::JsScript(_) + ) + } + Err(node) => { + if let Some(node) = JsPropertyClassMember::cast(node) { + node.modifiers().iter().any(|modifier| { + matches!(modifier, AnyJsPropertyModifier::JsStaticModifier(_)) + }) + } else { + true } - Err(node) => { - if let Some(node) = JsPropertyClassMember::cast(node) { - node.modifiers().iter().any(|modifier| { - matches!(modifier, AnyJsPropertyModifier::JsStaticModifier(_)) - }) - } else { - true - } - } - }); + } + } + }); if found_all_allowed { None } else { Some(()) } } diff --git a/crates/biome_js_analyze/src/lint/suspicious/no_var.rs b/crates/biome_js_analyze/src/lint/suspicious/no_var.rs index e18517c06c65..4315e4fa3cfe 100644 --- a/crates/biome_js_analyze/src/lint/suspicious/no_var.rs +++ b/crates/biome_js_analyze/src/lint/suspicious/no_var.rs @@ -59,6 +59,7 @@ impl Rule for NoVar { let ts_global_declaratio = &declaration .syntax() .ancestors() + .skip(1) .find_map(TsGlobalDeclaration::cast); if ts_global_declaratio.is_some() {