Skip to content

Commit 67c592b

Browse files
committed
feat(analyze/js/vue): add noVueArrowFuncInWatch
1 parent 391e88a commit 67c592b

File tree

20 files changed

+763
-93
lines changed

20 files changed

+763
-93
lines changed

.changeset/curly-jeans-fly.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@biomejs/biome": patch
3+
---
4+
5+
Added the new nursery rule [`noVueArrowFuncInWatch`](https://biomejs.dev/linter/rules/no-vue-arrow-func-in-watch/). This rule forbids using arrow functions in watchers in Vue components, because in an arrow function `this` won't reference the Vue instance.

crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/biome_configuration/src/analyzer/linter/rules.rs

Lines changed: 113 additions & 92 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/biome_configuration/src/generated/domain_selector.rs

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/biome_diagnostics_categories/src/categories.rs

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/biome_js_analyze/src/frameworks/vue/vue_component.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,11 @@ pub enum VueDeclarationCollectionFilter {
5959
Method = 1 << 5,
6060
/// Computed properties in a Vue component.
6161
Computed = 1 << 6,
62+
/// Watchers in a Vue component.
63+
Watcher = 1 << 7,
6264
}
6365

66+
#[derive(Debug)]
6467
pub struct VueComponent<'a> {
6568
kind: AnyVueComponent,
6669
path: &'a Utf8Path,
@@ -106,6 +109,7 @@ impl<'a> VueComponent<'a> {
106109

107110
/// An abstraction over multiple ways to define a vue component.
108111
/// Provides a list of declarations for a component.
112+
#[derive(Debug)]
109113
pub enum AnyVueComponent {
110114
/// Options API style Vue component.
111115
/// ```html
@@ -182,6 +186,7 @@ impl AnyVueComponent {
182186
/// ```html
183187
/// <script> export default { props: [ ... ], data: { ... }, ... }; </script>
184188
/// ```
189+
#[derive(Debug)]
185190
pub struct VueOptionsApiComponent {
186191
default_expression_clause: JsExportDefaultExpressionClause,
187192
}
@@ -190,6 +195,7 @@ pub struct VueOptionsApiComponent {
190195
/// ```js
191196
/// createApp({ props: [ ... ], ... });
192197
/// ```
198+
#[derive(Debug)]
193199
pub struct VueCreateApp {
194200
call_expression: JsCallExpression,
195201
}
@@ -199,6 +205,7 @@ pub struct VueCreateApp {
199205
/// defineComponent((...) => { ... }, { props: [ ... ], ... });
200206
/// defineComponent({ props: [ ... ], ... });
201207
/// ```
208+
#[derive(Debug)]
202209
pub struct VueDefineComponent {
203210
call_expression: JsCallExpression,
204211
}
@@ -207,6 +214,7 @@ pub struct VueDefineComponent {
207214
/// ```html
208215
/// <script setup> defineProps({ ... }); const someData = { ... }; </script>
209216
/// ```
217+
#[derive(Debug)]
210218
pub struct VueSetupComponent {
211219
model: SemanticModel,
212220
js_module: JsModule,
@@ -557,6 +565,15 @@ impl<T: VueOptionsApiBasedComponent> VueComponentDeclarations for T {
557565
.map(VueDeclaration::Setup),
558566
);
559567
}
568+
"watch" => {
569+
if !filter.contains(VueDeclarationCollectionFilter::Watcher) {
570+
continue;
571+
}
572+
result.extend(
573+
iter_declaration_group_properties(group_object_member)
574+
.map(VueDeclaration::Watcher),
575+
);
576+
}
560577
_ => {}
561578
}
562579
}
@@ -601,6 +618,18 @@ pub enum VueDeclaration {
601618
Method(AnyVueMethod),
602619
/// Computed properties in a Vue component.
603620
Computed(AnyVueMethod),
621+
/// Watchers in a Vue component.
622+
Watcher(JsPropertyObjectMember),
623+
}
624+
625+
impl VueDeclaration {
626+
pub fn as_watcher(&self) -> Option<&JsPropertyObjectMember> {
627+
if let Self::Watcher(watcher) = self {
628+
Some(watcher)
629+
} else {
630+
None
631+
}
632+
}
604633
}
605634

606635
pub trait VueDeclarationName {
@@ -622,6 +651,7 @@ impl VueDeclarationName for VueDeclaration {
622651
Self::Method(method_or_property) | Self::Computed(method_or_property) => {
623652
method_or_property.declaration_name()
624653
}
654+
Self::Watcher(object_property) => object_property.declaration_name(),
625655
}
626656
}
627657

@@ -636,6 +666,7 @@ impl VueDeclarationName for VueDeclaration {
636666
Self::Method(method_or_property) | Self::Computed(method_or_property) => {
637667
method_or_property.declaration_name_range()
638668
}
669+
Self::Watcher(object_property) => object_property.declaration_name_range(),
639670
}
640671
}
641672
}

crates/biome_js_analyze/src/lint/nursery.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ pub mod no_unresolved_imports;
3434
pub mod no_unused_expressions;
3535
pub mod no_useless_catch_binding;
3636
pub mod no_useless_undefined;
37+
pub mod no_vue_arrow_func_in_watch;
3738
pub mod no_vue_data_object_declaration;
3839
pub mod no_vue_duplicate_keys;
3940
pub mod no_vue_reserved_keys;
@@ -55,4 +56,4 @@ pub mod use_spread;
5556
pub mod use_vue_consistent_define_props_declaration;
5657
pub mod use_vue_define_macros_order;
5758
pub mod use_vue_multi_word_component_names;
58-
declare_lint_group! { pub Nursery { name : "nursery" , rules : [self :: no_ambiguous_anchor_text :: NoAmbiguousAnchorText , self :: no_continue :: NoContinue , self :: no_deprecated_imports :: NoDeprecatedImports , self :: no_duplicated_spread_props :: NoDuplicatedSpreadProps , self :: no_empty_source :: NoEmptySource , self :: no_equals_to_null :: NoEqualsToNull , self :: no_floating_promises :: NoFloatingPromises , self :: no_for_in :: NoForIn , self :: no_import_cycles :: NoImportCycles , self :: no_increment_decrement :: NoIncrementDecrement , self :: no_jsx_literals :: NoJsxLiterals , self :: no_leaked_render :: NoLeakedRender , self :: no_misused_promises :: NoMisusedPromises , self :: no_multi_assign :: NoMultiAssign , self :: no_multi_str :: NoMultiStr , self :: no_next_async_client_component :: NoNextAsyncClientComponent , self :: no_parameters_only_used_in_recursion :: NoParametersOnlyUsedInRecursion , self :: no_proto :: NoProto , self :: no_react_forward_ref :: NoReactForwardRef , self :: no_return_assign :: NoReturnAssign , self :: no_script_url :: NoScriptUrl , self :: no_shadow :: NoShadow , self :: no_sync_scripts :: NoSyncScripts , self :: no_ternary :: NoTernary , self :: no_undeclared_env_vars :: NoUndeclaredEnvVars , self :: no_unknown_attribute :: NoUnknownAttribute , self :: no_unnecessary_conditions :: NoUnnecessaryConditions , self :: no_unresolved_imports :: NoUnresolvedImports , self :: no_unused_expressions :: NoUnusedExpressions , self :: no_useless_catch_binding :: NoUselessCatchBinding , self :: no_useless_undefined :: NoUselessUndefined , self :: no_vue_data_object_declaration :: NoVueDataObjectDeclaration , self :: no_vue_duplicate_keys :: NoVueDuplicateKeys , self :: no_vue_reserved_keys :: NoVueReservedKeys , self :: no_vue_reserved_props :: NoVueReservedProps , self :: no_vue_setup_props_reactivity_loss :: NoVueSetupPropsReactivityLoss , self :: use_array_sort_compare :: UseArraySortCompare , self :: use_await_thenable :: UseAwaitThenable , self :: use_consistent_arrow_return :: UseConsistentArrowReturn , self :: use_destructuring :: UseDestructuring , self :: use_exhaustive_switch_cases :: UseExhaustiveSwitchCases , self :: use_explicit_type :: UseExplicitType , self :: use_find :: UseFind , self :: use_max_params :: UseMaxParams , self :: use_qwik_method_usage :: UseQwikMethodUsage , self :: use_qwik_valid_lexical_scope :: UseQwikValidLexicalScope , self :: use_regexp_exec :: UseRegexpExec , self :: use_sorted_classes :: UseSortedClasses , self :: use_spread :: UseSpread , self :: use_vue_consistent_define_props_declaration :: UseVueConsistentDefinePropsDeclaration , self :: use_vue_define_macros_order :: UseVueDefineMacrosOrder , self :: use_vue_multi_word_component_names :: UseVueMultiWordComponentNames ,] } }
59+
declare_lint_group! { pub Nursery { name : "nursery" , rules : [self :: no_ambiguous_anchor_text :: NoAmbiguousAnchorText , self :: no_continue :: NoContinue , self :: no_deprecated_imports :: NoDeprecatedImports , self :: no_duplicated_spread_props :: NoDuplicatedSpreadProps , self :: no_empty_source :: NoEmptySource , self :: no_equals_to_null :: NoEqualsToNull , self :: no_floating_promises :: NoFloatingPromises , self :: no_for_in :: NoForIn , self :: no_import_cycles :: NoImportCycles , self :: no_increment_decrement :: NoIncrementDecrement , self :: no_jsx_literals :: NoJsxLiterals , self :: no_leaked_render :: NoLeakedRender , self :: no_misused_promises :: NoMisusedPromises , self :: no_multi_assign :: NoMultiAssign , self :: no_multi_str :: NoMultiStr , self :: no_next_async_client_component :: NoNextAsyncClientComponent , self :: no_parameters_only_used_in_recursion :: NoParametersOnlyUsedInRecursion , self :: no_proto :: NoProto , self :: no_react_forward_ref :: NoReactForwardRef , self :: no_return_assign :: NoReturnAssign , self :: no_script_url :: NoScriptUrl , self :: no_shadow :: NoShadow , self :: no_sync_scripts :: NoSyncScripts , self :: no_ternary :: NoTernary , self :: no_undeclared_env_vars :: NoUndeclaredEnvVars , self :: no_unknown_attribute :: NoUnknownAttribute , self :: no_unnecessary_conditions :: NoUnnecessaryConditions , self :: no_unresolved_imports :: NoUnresolvedImports , self :: no_unused_expressions :: NoUnusedExpressions , self :: no_useless_catch_binding :: NoUselessCatchBinding , self :: no_useless_undefined :: NoUselessUndefined , self :: no_vue_arrow_func_in_watch :: NoVueArrowFuncInWatch , self :: no_vue_data_object_declaration :: NoVueDataObjectDeclaration , self :: no_vue_duplicate_keys :: NoVueDuplicateKeys , self :: no_vue_reserved_keys :: NoVueReservedKeys , self :: no_vue_reserved_props :: NoVueReservedProps , self :: no_vue_setup_props_reactivity_loss :: NoVueSetupPropsReactivityLoss , self :: use_array_sort_compare :: UseArraySortCompare , self :: use_await_thenable :: UseAwaitThenable , self :: use_consistent_arrow_return :: UseConsistentArrowReturn , self :: use_destructuring :: UseDestructuring , self :: use_exhaustive_switch_cases :: UseExhaustiveSwitchCases , self :: use_explicit_type :: UseExplicitType , self :: use_find :: UseFind , self :: use_max_params :: UseMaxParams , self :: use_qwik_method_usage :: UseQwikMethodUsage , self :: use_qwik_valid_lexical_scope :: UseQwikValidLexicalScope , self :: use_regexp_exec :: UseRegexpExec , self :: use_sorted_classes :: UseSortedClasses , self :: use_spread :: UseSpread , self :: use_vue_consistent_define_props_declaration :: UseVueConsistentDefinePropsDeclaration , self :: use_vue_define_macros_order :: UseVueDefineMacrosOrder , self :: use_vue_multi_word_component_names :: UseVueMultiWordComponentNames ,] } }

0 commit comments

Comments
 (0)