diff --git a/.changeset/slick-masks-wear.md b/.changeset/slick-masks-wear.md new file mode 100644 index 000000000000..9fdb9952e377 --- /dev/null +++ b/.changeset/slick-masks-wear.md @@ -0,0 +1,13 @@ +--- +"@biomejs/biome": patch +--- + +Added new nursery rule [`noReturnAssign`](https://biomejs.dev/linter/rules/no-return-assign), which disallows assignments inside return statements. + +**Invalid:** + +```js +function f(a) { + return a = 1; +} +``` diff --git a/crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs b/crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs index e9eb9de36a51..e42b6254852a 100644 --- a/crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs +++ b/crates/biome_cli/src/execute/migrate/eslint_any_rule_to_biome.rs @@ -1937,6 +1937,18 @@ pub(crate) fn migrate_eslint_any_rule( .get_or_insert(Default::default()); rule.set_level(rule.level().max(rule_severity.into())); } + "no-return-assign" => { + if !options.include_nursery { + results.add(eslint_name, eslint_to_biome::RuleMigrationResult::Nursery); + return false; + } + let group = rules.nursery.get_or_insert_with(Default::default); + let rule = group + .unwrap_group_as_mut() + .no_return_assign + .get_or_insert(Default::default()); + rule.set_level(rule.level().max(rule_severity.into())); + } "no-script-url" => { if !options.include_nursery { results.add(eslint_name, eslint_to_biome::RuleMigrationResult::Nursery); diff --git a/crates/biome_configuration/src/analyzer/linter/rules.rs b/crates/biome_configuration/src/analyzer/linter/rules.rs index 9f65eb68ce7f..5b176964a694 100644 --- a/crates/biome_configuration/src/analyzer/linter/rules.rs +++ b/crates/biome_configuration/src/analyzer/linter/rules.rs @@ -259,6 +259,7 @@ pub enum RuleName { NoRestrictedGlobals, NoRestrictedImports, NoRestrictedTypes, + NoReturnAssign, NoScriptUrl, NoSecrets, NoSelfAssign, @@ -665,6 +666,7 @@ impl RuleName { Self::NoRestrictedGlobals => "noRestrictedGlobals", Self::NoRestrictedImports => "noRestrictedImports", Self::NoRestrictedTypes => "noRestrictedTypes", + Self::NoReturnAssign => "noReturnAssign", Self::NoScriptUrl => "noScriptUrl", Self::NoSecrets => "noSecrets", Self::NoSelfAssign => "noSelfAssign", @@ -1069,6 +1071,7 @@ impl RuleName { Self::NoRestrictedGlobals => RuleGroup::Style, Self::NoRestrictedImports => RuleGroup::Style, Self::NoRestrictedTypes => RuleGroup::Style, + Self::NoReturnAssign => RuleGroup::Nursery, Self::NoScriptUrl => RuleGroup::Nursery, Self::NoSecrets => RuleGroup::Security, Self::NoSelfAssign => RuleGroup::Correctness, @@ -1480,6 +1483,7 @@ impl std::str::FromStr for RuleName { "noRestrictedGlobals" => Ok(Self::NoRestrictedGlobals), "noRestrictedImports" => Ok(Self::NoRestrictedImports), "noRestrictedTypes" => Ok(Self::NoRestrictedTypes), + "noReturnAssign" => Ok(Self::NoReturnAssign), "noScriptUrl" => Ok(Self::NoScriptUrl), "noSecrets" => Ok(Self::NoSecrets), "noSelfAssign" => Ok(Self::NoSelfAssign), @@ -4844,7 +4848,7 @@ impl From for Correctness { #[cfg_attr(feature = "schema", derive(JsonSchema))] #[serde(rename_all = "camelCase", default, deny_unknown_fields)] #[doc = r" A list of rules that belong to this group"] -pub struct Nursery { # [doc = r" Enables the recommended rules for this group"] # [serde (skip_serializing_if = "Option::is_none")] pub recommended : Option < bool > , # [doc = "Disallow ambiguous anchor descriptions.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_ambiguous_anchor_text : Option < RuleConfiguration < biome_rule_options :: no_ambiguous_anchor_text :: NoAmbiguousAnchorTextOptions >> , # [doc = "Disallow continue statements.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_continue : Option < RuleConfiguration < biome_rule_options :: no_continue :: NoContinueOptions >> , # [doc = "Restrict imports of deprecated exports.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_deprecated_imports : Option < RuleConfiguration < biome_rule_options :: no_deprecated_imports :: NoDeprecatedImportsOptions >> , # [doc = "Prevent the listing of duplicate dependencies. The rule supports the following dependency groups: \"bundledDependencies\", \"bundleDependencies\", \"dependencies\", \"devDependencies\", \"overrides\", \"optionalDependencies\", and \"peerDependencies\".\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_duplicate_dependencies : Option < RuleConfiguration < biome_rule_options :: no_duplicate_dependencies :: NoDuplicateDependenciesOptions >> , # [doc = "Disallow JSX prop spreading the same identifier multiple times.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_duplicated_spread_props : Option < RuleConfiguration < biome_rule_options :: no_duplicated_spread_props :: NoDuplicatedSpreadPropsOptions >> , # [doc = "Disallow empty sources.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_empty_source : Option < RuleConfiguration < biome_rule_options :: no_empty_source :: NoEmptySourceOptions >> , # [doc = "Require the use of === or !== for comparison with null.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_equals_to_null : Option < RuleFixConfiguration < biome_rule_options :: no_equals_to_null :: NoEqualsToNullOptions >> , # [doc = "Require Promise-like statements to be handled appropriately.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_floating_promises : Option < RuleFixConfiguration < biome_rule_options :: no_floating_promises :: NoFloatingPromisesOptions >> , # [doc = "Disallow iterating using a for-in loop.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_for_in : Option < RuleConfiguration < biome_rule_options :: no_for_in :: NoForInOptions >> , # [doc = "Prevent import cycles.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_import_cycles : Option < RuleConfiguration < biome_rule_options :: no_import_cycles :: NoImportCyclesOptions >> , # [doc = "Disallows the usage of the unary operators ++ and --.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_increment_decrement : Option < RuleConfiguration < biome_rule_options :: no_increment_decrement :: NoIncrementDecrementOptions >> , # [doc = "Disallow string literals inside JSX elements.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_jsx_literals : Option < RuleConfiguration < biome_rule_options :: no_jsx_literals :: NoJsxLiteralsOptions >> , # [doc = "Prevent problematic leaked values from being rendered.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_leaked_render : Option < RuleConfiguration < biome_rule_options :: no_leaked_render :: NoLeakedRenderOptions >> , # [doc = "Disallow Promises to be used in places where they are almost certainly a mistake.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_misused_promises : Option < RuleFixConfiguration < biome_rule_options :: no_misused_promises :: NoMisusedPromisesOptions >> , # [doc = "Disallow use of chained assignment expressions.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_multi_assign : Option < RuleConfiguration < biome_rule_options :: no_multi_assign :: NoMultiAssignOptions >> , # [doc = "Disallow creating multiline strings by escaping newlines.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_multi_str : Option < RuleConfiguration < biome_rule_options :: no_multi_str :: NoMultiStrOptions >> , # [doc = "Prevent client components from being async functions.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_next_async_client_component : Option < RuleConfiguration < biome_rule_options :: no_next_async_client_component :: NoNextAsyncClientComponentOptions >> , # [doc = "Disallow function parameters that are only used in recursive calls.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_parameters_only_used_in_recursion : Option < RuleFixConfiguration < biome_rule_options :: no_parameters_only_used_in_recursion :: NoParametersOnlyUsedInRecursionOptions >> , # [doc = "Disallow the use of the deprecated __proto__ object property.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_proto : Option < RuleConfiguration < biome_rule_options :: no_proto :: NoProtoOptions >> , # [doc = "Replaces usages of forwardRef with passing ref as a prop.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_react_forward_ref : Option < RuleFixConfiguration < biome_rule_options :: no_react_forward_ref :: NoReactForwardRefOptions >> , # [doc = "Disallow javascript: URLs in HTML.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_script_url : Option < RuleConfiguration < biome_rule_options :: no_script_url :: NoScriptUrlOptions >> , # [doc = "Disallow variable declarations from shadowing variables declared in the outer scope.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_shadow : Option < RuleConfiguration < biome_rule_options :: no_shadow :: NoShadowOptions >> , # [doc = "Prevent the usage of synchronous scripts.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_sync_scripts : Option < RuleConfiguration < biome_rule_options :: no_sync_scripts :: NoSyncScriptsOptions >> , # [doc = "Disallow ternary operators.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_ternary : Option < RuleConfiguration < biome_rule_options :: no_ternary :: NoTernaryOptions >> , # [doc = "Disallow the use of undeclared environment variables.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_undeclared_env_vars : Option < RuleConfiguration < biome_rule_options :: no_undeclared_env_vars :: NoUndeclaredEnvVarsOptions >> , # [doc = "Disallow unknown DOM properties.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_unknown_attribute : Option < RuleConfiguration < biome_rule_options :: no_unknown_attribute :: NoUnknownAttributeOptions >> , # [doc = "Disallow unnecessary type-based conditions that can be statically determined as redundant.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_unnecessary_conditions : Option < RuleConfiguration < biome_rule_options :: no_unnecessary_conditions :: NoUnnecessaryConditionsOptions >> , # [doc = "Warn when importing non-existing exports.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_unresolved_imports : Option < RuleConfiguration < biome_rule_options :: no_unresolved_imports :: NoUnresolvedImportsOptions >> , # [doc = "Disallow expression statements that are neither a function call nor an assignment.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_unused_expressions : Option < RuleConfiguration < biome_rule_options :: no_unused_expressions :: NoUnusedExpressionsOptions >> , # [doc = "Disallow unused catch bindings.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_useless_catch_binding : Option < RuleFixConfiguration < biome_rule_options :: no_useless_catch_binding :: NoUselessCatchBindingOptions >> , # [doc = "Disallow the use of useless undefined.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_useless_undefined : Option < RuleFixConfiguration < biome_rule_options :: no_useless_undefined :: NoUselessUndefinedOptions >> , # [doc = "Enforce that Vue component data options are declared as functions.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_vue_data_object_declaration : Option < RuleFixConfiguration < biome_rule_options :: no_vue_data_object_declaration :: NoVueDataObjectDeclarationOptions >> , # [doc = "Disallow duplicate keys in Vue component data, methods, computed properties, and other options.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_vue_duplicate_keys : Option < RuleConfiguration < biome_rule_options :: no_vue_duplicate_keys :: NoVueDuplicateKeysOptions >> , # [doc = "Disallow reserved keys in Vue component data and computed properties.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_vue_reserved_keys : Option < RuleConfiguration < biome_rule_options :: no_vue_reserved_keys :: NoVueReservedKeysOptions >> , # [doc = "Disallow reserved names to be used as props.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_vue_reserved_props : Option < RuleConfiguration < biome_rule_options :: no_vue_reserved_props :: NoVueReservedPropsOptions >> , # [doc = "Disallow destructuring of props passed to setup in Vue projects.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_vue_setup_props_reactivity_loss : Option < RuleConfiguration < biome_rule_options :: no_vue_setup_props_reactivity_loss :: NoVueSetupPropsReactivityLossOptions >> , # [doc = "Disallow using v-if and v-for directives on the same element.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_vue_v_if_with_v_for : Option < RuleConfiguration < biome_rule_options :: no_vue_v_if_with_v_for :: NoVueVIfWithVForOptions >> , # [doc = "Require Array#sort and Array#toSorted calls to always provide a compareFunction.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_array_sort_compare : Option < RuleConfiguration < biome_rule_options :: use_array_sort_compare :: UseArraySortCompareOptions >> , # [doc = "Enforce that await is only used on Promise values.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_await_thenable : Option < RuleConfiguration < biome_rule_options :: use_await_thenable :: UseAwaitThenableOptions >> , # [doc = "Enforce consistent arrow function bodies.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_consistent_arrow_return : Option < RuleFixConfiguration < biome_rule_options :: use_consistent_arrow_return :: UseConsistentArrowReturnOptions >> , # [doc = "Require all descriptions to follow the same style (either block or inline) to maintain consistency and improve readability across the schema.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_consistent_graphql_descriptions : Option < RuleConfiguration < biome_rule_options :: use_consistent_graphql_descriptions :: UseConsistentGraphqlDescriptionsOptions >> , # [doc = "Require the @deprecated directive to specify a deletion date.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_deprecated_date : Option < RuleConfiguration < biome_rule_options :: use_deprecated_date :: UseDeprecatedDateOptions >> , # [doc = "Require destructuring from arrays and/or objects.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_destructuring : Option < RuleConfiguration < biome_rule_options :: use_destructuring :: UseDestructuringOptions >> , # [doc = "Require switch-case statements to be exhaustive.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_exhaustive_switch_cases : Option < RuleFixConfiguration < biome_rule_options :: use_exhaustive_switch_cases :: UseExhaustiveSwitchCasesOptions >> , # [doc = "Enforce types in functions, methods, variables, and parameters.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_explicit_type : Option < RuleConfiguration < biome_rule_options :: use_explicit_type :: UseExplicitTypeOptions >> , # [doc = "Enforce the use of Array.prototype.find() over Array.prototype.filter() followed by [0] when looking for a single result.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_find : Option < RuleConfiguration < biome_rule_options :: use_find :: UseFindOptions >> , # [doc = "Enforce a maximum number of parameters in function definitions.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_max_params : Option < RuleConfiguration < biome_rule_options :: use_max_params :: UseMaxParamsOptions >> , # [doc = "Disallow use* hooks outside of component$ or other use* hooks in Qwik applications.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_qwik_method_usage : Option < RuleConfiguration < biome_rule_options :: use_qwik_method_usage :: UseQwikMethodUsageOptions >> , # [doc = "Disallow unserializable expressions in Qwik dollar ($) scopes.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_qwik_valid_lexical_scope : Option < RuleConfiguration < biome_rule_options :: use_qwik_valid_lexical_scope :: UseQwikValidLexicalScopeOptions >> , # [doc = "Enforce RegExp#exec over String#match if no global flag is provided.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_regexp_exec : Option < RuleConfiguration < biome_rule_options :: use_regexp_exec :: UseRegexpExecOptions >> , # [doc = "Enforce the presence of required scripts in package.json.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_required_scripts : Option < RuleConfiguration < biome_rule_options :: use_required_scripts :: UseRequiredScriptsOptions >> , # [doc = "Enforce the sorting of CSS utility classes.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_sorted_classes : Option < RuleFixConfiguration < biome_rule_options :: use_sorted_classes :: UseSortedClassesOptions >> , # [doc = "Enforce the use of the spread operator over .apply().\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_spread : Option < RuleFixConfiguration < biome_rule_options :: use_spread :: UseSpreadOptions >> , # [doc = "Enforce unique operation names across a GraphQL document.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_unique_graphql_operation_name : Option < RuleConfiguration < biome_rule_options :: use_unique_graphql_operation_name :: UseUniqueGraphqlOperationNameOptions >> , # [doc = "Enforce consistent defineProps declaration style.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_vue_consistent_define_props_declaration : Option < RuleConfiguration < biome_rule_options :: use_vue_consistent_define_props_declaration :: UseVueConsistentDefinePropsDeclarationOptions >> , # [doc = "Enforce specific order of Vue compiler macros.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_vue_define_macros_order : Option < RuleFixConfiguration < biome_rule_options :: use_vue_define_macros_order :: UseVueDefineMacrosOrderOptions >> , # [doc = "Enforce hyphenated (kebab-case) attribute names in Vue templates.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_vue_hyphenated_attributes : Option < RuleFixConfiguration < biome_rule_options :: use_vue_hyphenated_attributes :: UseVueHyphenatedAttributesOptions >> , # [doc = "Enforce multi-word component names in Vue components.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_vue_multi_word_component_names : Option < RuleConfiguration < biome_rule_options :: use_vue_multi_word_component_names :: UseVueMultiWordComponentNamesOptions >> , # [doc = "Forbids v-bind directives with missing arguments or invalid modifiers.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_vue_valid_v_bind : Option < RuleConfiguration < biome_rule_options :: use_vue_valid_v_bind :: UseVueValidVBindOptions >> , # [doc = "Enforce valid usage of v-else.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_vue_valid_v_else : Option < RuleConfiguration < biome_rule_options :: use_vue_valid_v_else :: UseVueValidVElseOptions >> , # [doc = "Enforce valid v-else-if directives.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_vue_valid_v_else_if : Option < RuleConfiguration < biome_rule_options :: use_vue_valid_v_else_if :: UseVueValidVElseIfOptions >> , # [doc = "Enforce valid v-html directives.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_vue_valid_v_html : Option < RuleConfiguration < biome_rule_options :: use_vue_valid_v_html :: UseVueValidVHtmlOptions >> , # [doc = "Enforces valid v-if usage for Vue templates.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_vue_valid_v_if : Option < RuleConfiguration < biome_rule_options :: use_vue_valid_v_if :: UseVueValidVIfOptions >> , # [doc = "Enforce valid v-on directives with proper arguments, modifiers, and handlers.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_vue_valid_v_on : Option < RuleConfiguration < biome_rule_options :: use_vue_valid_v_on :: UseVueValidVOnOptions >> , # [doc = "Enforce valid v-text Vue directives.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_vue_valid_v_text : Option < RuleConfiguration < biome_rule_options :: use_vue_valid_v_text :: UseVueValidVTextOptions >> } +pub struct Nursery { # [doc = r" Enables the recommended rules for this group"] # [serde (skip_serializing_if = "Option::is_none")] pub recommended : Option < bool > , # [doc = "Disallow ambiguous anchor descriptions.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_ambiguous_anchor_text : Option < RuleConfiguration < biome_rule_options :: no_ambiguous_anchor_text :: NoAmbiguousAnchorTextOptions >> , # [doc = "Disallow continue statements.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_continue : Option < RuleConfiguration < biome_rule_options :: no_continue :: NoContinueOptions >> , # [doc = "Restrict imports of deprecated exports.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_deprecated_imports : Option < RuleConfiguration < biome_rule_options :: no_deprecated_imports :: NoDeprecatedImportsOptions >> , # [doc = "Prevent the listing of duplicate dependencies. The rule supports the following dependency groups: \"bundledDependencies\", \"bundleDependencies\", \"dependencies\", \"devDependencies\", \"overrides\", \"optionalDependencies\", and \"peerDependencies\".\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_duplicate_dependencies : Option < RuleConfiguration < biome_rule_options :: no_duplicate_dependencies :: NoDuplicateDependenciesOptions >> , # [doc = "Disallow JSX prop spreading the same identifier multiple times.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_duplicated_spread_props : Option < RuleConfiguration < biome_rule_options :: no_duplicated_spread_props :: NoDuplicatedSpreadPropsOptions >> , # [doc = "Disallow empty sources.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_empty_source : Option < RuleConfiguration < biome_rule_options :: no_empty_source :: NoEmptySourceOptions >> , # [doc = "Require the use of === or !== for comparison with null.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_equals_to_null : Option < RuleFixConfiguration < biome_rule_options :: no_equals_to_null :: NoEqualsToNullOptions >> , # [doc = "Require Promise-like statements to be handled appropriately.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_floating_promises : Option < RuleFixConfiguration < biome_rule_options :: no_floating_promises :: NoFloatingPromisesOptions >> , # [doc = "Disallow iterating using a for-in loop.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_for_in : Option < RuleConfiguration < biome_rule_options :: no_for_in :: NoForInOptions >> , # [doc = "Prevent import cycles.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_import_cycles : Option < RuleConfiguration < biome_rule_options :: no_import_cycles :: NoImportCyclesOptions >> , # [doc = "Disallows the usage of the unary operators ++ and --.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_increment_decrement : Option < RuleConfiguration < biome_rule_options :: no_increment_decrement :: NoIncrementDecrementOptions >> , # [doc = "Disallow string literals inside JSX elements.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_jsx_literals : Option < RuleConfiguration < biome_rule_options :: no_jsx_literals :: NoJsxLiteralsOptions >> , # [doc = "Prevent problematic leaked values from being rendered.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_leaked_render : Option < RuleConfiguration < biome_rule_options :: no_leaked_render :: NoLeakedRenderOptions >> , # [doc = "Disallow Promises to be used in places where they are almost certainly a mistake.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_misused_promises : Option < RuleFixConfiguration < biome_rule_options :: no_misused_promises :: NoMisusedPromisesOptions >> , # [doc = "Disallow use of chained assignment expressions.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_multi_assign : Option < RuleConfiguration < biome_rule_options :: no_multi_assign :: NoMultiAssignOptions >> , # [doc = "Disallow creating multiline strings by escaping newlines.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_multi_str : Option < RuleConfiguration < biome_rule_options :: no_multi_str :: NoMultiStrOptions >> , # [doc = "Prevent client components from being async functions.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_next_async_client_component : Option < RuleConfiguration < biome_rule_options :: no_next_async_client_component :: NoNextAsyncClientComponentOptions >> , # [doc = "Disallow function parameters that are only used in recursive calls.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_parameters_only_used_in_recursion : Option < RuleFixConfiguration < biome_rule_options :: no_parameters_only_used_in_recursion :: NoParametersOnlyUsedInRecursionOptions >> , # [doc = "Disallow the use of the deprecated __proto__ object property.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_proto : Option < RuleConfiguration < biome_rule_options :: no_proto :: NoProtoOptions >> , # [doc = "Replaces usages of forwardRef with passing ref as a prop.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_react_forward_ref : Option < RuleFixConfiguration < biome_rule_options :: no_react_forward_ref :: NoReactForwardRefOptions >> , # [doc = "Disallow assignments in return statements.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_return_assign : Option < RuleConfiguration < biome_rule_options :: no_return_assign :: NoReturnAssignOptions >> , # [doc = "Disallow javascript: URLs in HTML.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_script_url : Option < RuleConfiguration < biome_rule_options :: no_script_url :: NoScriptUrlOptions >> , # [doc = "Disallow variable declarations from shadowing variables declared in the outer scope.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_shadow : Option < RuleConfiguration < biome_rule_options :: no_shadow :: NoShadowOptions >> , # [doc = "Prevent the usage of synchronous scripts.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_sync_scripts : Option < RuleConfiguration < biome_rule_options :: no_sync_scripts :: NoSyncScriptsOptions >> , # [doc = "Disallow ternary operators.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_ternary : Option < RuleConfiguration < biome_rule_options :: no_ternary :: NoTernaryOptions >> , # [doc = "Disallow the use of undeclared environment variables.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_undeclared_env_vars : Option < RuleConfiguration < biome_rule_options :: no_undeclared_env_vars :: NoUndeclaredEnvVarsOptions >> , # [doc = "Disallow unknown DOM properties.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_unknown_attribute : Option < RuleConfiguration < biome_rule_options :: no_unknown_attribute :: NoUnknownAttributeOptions >> , # [doc = "Disallow unnecessary type-based conditions that can be statically determined as redundant.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_unnecessary_conditions : Option < RuleConfiguration < biome_rule_options :: no_unnecessary_conditions :: NoUnnecessaryConditionsOptions >> , # [doc = "Warn when importing non-existing exports.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_unresolved_imports : Option < RuleConfiguration < biome_rule_options :: no_unresolved_imports :: NoUnresolvedImportsOptions >> , # [doc = "Disallow expression statements that are neither a function call nor an assignment.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_unused_expressions : Option < RuleConfiguration < biome_rule_options :: no_unused_expressions :: NoUnusedExpressionsOptions >> , # [doc = "Disallow unused catch bindings.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_useless_catch_binding : Option < RuleFixConfiguration < biome_rule_options :: no_useless_catch_binding :: NoUselessCatchBindingOptions >> , # [doc = "Disallow the use of useless undefined.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_useless_undefined : Option < RuleFixConfiguration < biome_rule_options :: no_useless_undefined :: NoUselessUndefinedOptions >> , # [doc = "Enforce that Vue component data options are declared as functions.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_vue_data_object_declaration : Option < RuleFixConfiguration < biome_rule_options :: no_vue_data_object_declaration :: NoVueDataObjectDeclarationOptions >> , # [doc = "Disallow duplicate keys in Vue component data, methods, computed properties, and other options.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_vue_duplicate_keys : Option < RuleConfiguration < biome_rule_options :: no_vue_duplicate_keys :: NoVueDuplicateKeysOptions >> , # [doc = "Disallow reserved keys in Vue component data and computed properties.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_vue_reserved_keys : Option < RuleConfiguration < biome_rule_options :: no_vue_reserved_keys :: NoVueReservedKeysOptions >> , # [doc = "Disallow reserved names to be used as props.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_vue_reserved_props : Option < RuleConfiguration < biome_rule_options :: no_vue_reserved_props :: NoVueReservedPropsOptions >> , # [doc = "Disallow destructuring of props passed to setup in Vue projects.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_vue_setup_props_reactivity_loss : Option < RuleConfiguration < biome_rule_options :: no_vue_setup_props_reactivity_loss :: NoVueSetupPropsReactivityLossOptions >> , # [doc = "Disallow using v-if and v-for directives on the same element.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub no_vue_v_if_with_v_for : Option < RuleConfiguration < biome_rule_options :: no_vue_v_if_with_v_for :: NoVueVIfWithVForOptions >> , # [doc = "Require Array#sort and Array#toSorted calls to always provide a compareFunction.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_array_sort_compare : Option < RuleConfiguration < biome_rule_options :: use_array_sort_compare :: UseArraySortCompareOptions >> , # [doc = "Enforce that await is only used on Promise values.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_await_thenable : Option < RuleConfiguration < biome_rule_options :: use_await_thenable :: UseAwaitThenableOptions >> , # [doc = "Enforce consistent arrow function bodies.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_consistent_arrow_return : Option < RuleFixConfiguration < biome_rule_options :: use_consistent_arrow_return :: UseConsistentArrowReturnOptions >> , # [doc = "Require all descriptions to follow the same style (either block or inline) to maintain consistency and improve readability across the schema.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_consistent_graphql_descriptions : Option < RuleConfiguration < biome_rule_options :: use_consistent_graphql_descriptions :: UseConsistentGraphqlDescriptionsOptions >> , # [doc = "Require the @deprecated directive to specify a deletion date.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_deprecated_date : Option < RuleConfiguration < biome_rule_options :: use_deprecated_date :: UseDeprecatedDateOptions >> , # [doc = "Require destructuring from arrays and/or objects.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_destructuring : Option < RuleConfiguration < biome_rule_options :: use_destructuring :: UseDestructuringOptions >> , # [doc = "Require switch-case statements to be exhaustive.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_exhaustive_switch_cases : Option < RuleFixConfiguration < biome_rule_options :: use_exhaustive_switch_cases :: UseExhaustiveSwitchCasesOptions >> , # [doc = "Enforce types in functions, methods, variables, and parameters.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_explicit_type : Option < RuleConfiguration < biome_rule_options :: use_explicit_type :: UseExplicitTypeOptions >> , # [doc = "Enforce the use of Array.prototype.find() over Array.prototype.filter() followed by [0] when looking for a single result.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_find : Option < RuleConfiguration < biome_rule_options :: use_find :: UseFindOptions >> , # [doc = "Enforce a maximum number of parameters in function definitions.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_max_params : Option < RuleConfiguration < biome_rule_options :: use_max_params :: UseMaxParamsOptions >> , # [doc = "Disallow use* hooks outside of component$ or other use* hooks in Qwik applications.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_qwik_method_usage : Option < RuleConfiguration < biome_rule_options :: use_qwik_method_usage :: UseQwikMethodUsageOptions >> , # [doc = "Disallow unserializable expressions in Qwik dollar ($) scopes.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_qwik_valid_lexical_scope : Option < RuleConfiguration < biome_rule_options :: use_qwik_valid_lexical_scope :: UseQwikValidLexicalScopeOptions >> , # [doc = "Enforce RegExp#exec over String#match if no global flag is provided.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_regexp_exec : Option < RuleConfiguration < biome_rule_options :: use_regexp_exec :: UseRegexpExecOptions >> , # [doc = "Enforce the presence of required scripts in package.json.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_required_scripts : Option < RuleConfiguration < biome_rule_options :: use_required_scripts :: UseRequiredScriptsOptions >> , # [doc = "Enforce the sorting of CSS utility classes.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_sorted_classes : Option < RuleFixConfiguration < biome_rule_options :: use_sorted_classes :: UseSortedClassesOptions >> , # [doc = "Enforce the use of the spread operator over .apply().\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_spread : Option < RuleFixConfiguration < biome_rule_options :: use_spread :: UseSpreadOptions >> , # [doc = "Enforce unique operation names across a GraphQL document.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_unique_graphql_operation_name : Option < RuleConfiguration < biome_rule_options :: use_unique_graphql_operation_name :: UseUniqueGraphqlOperationNameOptions >> , # [doc = "Enforce consistent defineProps declaration style.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_vue_consistent_define_props_declaration : Option < RuleConfiguration < biome_rule_options :: use_vue_consistent_define_props_declaration :: UseVueConsistentDefinePropsDeclarationOptions >> , # [doc = "Enforce specific order of Vue compiler macros.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_vue_define_macros_order : Option < RuleFixConfiguration < biome_rule_options :: use_vue_define_macros_order :: UseVueDefineMacrosOrderOptions >> , # [doc = "Enforce hyphenated (kebab-case) attribute names in Vue templates.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_vue_hyphenated_attributes : Option < RuleFixConfiguration < biome_rule_options :: use_vue_hyphenated_attributes :: UseVueHyphenatedAttributesOptions >> , # [doc = "Enforce multi-word component names in Vue components.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_vue_multi_word_component_names : Option < RuleConfiguration < biome_rule_options :: use_vue_multi_word_component_names :: UseVueMultiWordComponentNamesOptions >> , # [doc = "Forbids v-bind directives with missing arguments or invalid modifiers.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_vue_valid_v_bind : Option < RuleConfiguration < biome_rule_options :: use_vue_valid_v_bind :: UseVueValidVBindOptions >> , # [doc = "Enforce valid usage of v-else.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_vue_valid_v_else : Option < RuleConfiguration < biome_rule_options :: use_vue_valid_v_else :: UseVueValidVElseOptions >> , # [doc = "Enforce valid v-else-if directives.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_vue_valid_v_else_if : Option < RuleConfiguration < biome_rule_options :: use_vue_valid_v_else_if :: UseVueValidVElseIfOptions >> , # [doc = "Enforce valid v-html directives.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_vue_valid_v_html : Option < RuleConfiguration < biome_rule_options :: use_vue_valid_v_html :: UseVueValidVHtmlOptions >> , # [doc = "Enforces valid v-if usage for Vue templates.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_vue_valid_v_if : Option < RuleConfiguration < biome_rule_options :: use_vue_valid_v_if :: UseVueValidVIfOptions >> , # [doc = "Enforce valid v-on directives with proper arguments, modifiers, and handlers.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_vue_valid_v_on : Option < RuleConfiguration < biome_rule_options :: use_vue_valid_v_on :: UseVueValidVOnOptions >> , # [doc = "Enforce valid v-text Vue directives.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_vue_valid_v_text : Option < RuleConfiguration < biome_rule_options :: use_vue_valid_v_text :: UseVueValidVTextOptions >> } impl Nursery { const GROUP_NAME: &'static str = "nursery"; pub(crate) const GROUP_RULES: &'static [&'static str] = &[ @@ -4868,6 +4872,7 @@ impl Nursery { "noParametersOnlyUsedInRecursion", "noProto", "noReactForwardRef", + "noReturnAssign", "noScriptUrl", "noShadow", "noSyncScripts", @@ -4916,8 +4921,8 @@ impl Nursery { ]; const RECOMMENDED_RULES_AS_FILTERS: &'static [RuleFilter<'static>] = &[ RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[18]), - RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[20]), - RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[52]), + RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[21]), + RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[53]), ]; const ALL_RULES_AS_FILTERS: &'static [RuleFilter<'static>] = &[ RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[0]), @@ -4985,6 +4990,7 @@ impl Nursery { RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[62]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[63]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[64]), + RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[65]), ]; } impl RuleGroupExt for Nursery { @@ -5096,231 +5102,236 @@ impl RuleGroupExt for Nursery { { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[19])); } - if let Some(rule) = self.no_script_url.as_ref() + if let Some(rule) = self.no_return_assign.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[20])); } - if let Some(rule) = self.no_shadow.as_ref() + if let Some(rule) = self.no_script_url.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[21])); } - if let Some(rule) = self.no_sync_scripts.as_ref() + if let Some(rule) = self.no_shadow.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[22])); } - if let Some(rule) = self.no_ternary.as_ref() + if let Some(rule) = self.no_sync_scripts.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[23])); } - if let Some(rule) = self.no_undeclared_env_vars.as_ref() + if let Some(rule) = self.no_ternary.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[24])); } - if let Some(rule) = self.no_unknown_attribute.as_ref() + if let Some(rule) = self.no_undeclared_env_vars.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[25])); } - if let Some(rule) = self.no_unnecessary_conditions.as_ref() + if let Some(rule) = self.no_unknown_attribute.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[26])); } - if let Some(rule) = self.no_unresolved_imports.as_ref() + if let Some(rule) = self.no_unnecessary_conditions.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[27])); } - if let Some(rule) = self.no_unused_expressions.as_ref() + if let Some(rule) = self.no_unresolved_imports.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[28])); } - if let Some(rule) = self.no_useless_catch_binding.as_ref() + if let Some(rule) = self.no_unused_expressions.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[29])); } - if let Some(rule) = self.no_useless_undefined.as_ref() + if let Some(rule) = self.no_useless_catch_binding.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[30])); } - if let Some(rule) = self.no_vue_data_object_declaration.as_ref() + if let Some(rule) = self.no_useless_undefined.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[31])); } - if let Some(rule) = self.no_vue_duplicate_keys.as_ref() + if let Some(rule) = self.no_vue_data_object_declaration.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[32])); } - if let Some(rule) = self.no_vue_reserved_keys.as_ref() + if let Some(rule) = self.no_vue_duplicate_keys.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[33])); } - if let Some(rule) = self.no_vue_reserved_props.as_ref() + if let Some(rule) = self.no_vue_reserved_keys.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[34])); } - if let Some(rule) = self.no_vue_setup_props_reactivity_loss.as_ref() + if let Some(rule) = self.no_vue_reserved_props.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[35])); } - if let Some(rule) = self.no_vue_v_if_with_v_for.as_ref() + if let Some(rule) = self.no_vue_setup_props_reactivity_loss.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[36])); } - if let Some(rule) = self.use_array_sort_compare.as_ref() + if let Some(rule) = self.no_vue_v_if_with_v_for.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[37])); } - if let Some(rule) = self.use_await_thenable.as_ref() + if let Some(rule) = self.use_array_sort_compare.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[38])); } - if let Some(rule) = self.use_consistent_arrow_return.as_ref() + if let Some(rule) = self.use_await_thenable.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[39])); } - if let Some(rule) = self.use_consistent_graphql_descriptions.as_ref() + if let Some(rule) = self.use_consistent_arrow_return.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[40])); } - if let Some(rule) = self.use_deprecated_date.as_ref() + if let Some(rule) = self.use_consistent_graphql_descriptions.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[41])); } - if let Some(rule) = self.use_destructuring.as_ref() + if let Some(rule) = self.use_deprecated_date.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[42])); } - if let Some(rule) = self.use_exhaustive_switch_cases.as_ref() + if let Some(rule) = self.use_destructuring.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[43])); } - if let Some(rule) = self.use_explicit_type.as_ref() + if let Some(rule) = self.use_exhaustive_switch_cases.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[44])); } - if let Some(rule) = self.use_find.as_ref() + if let Some(rule) = self.use_explicit_type.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[45])); } - if let Some(rule) = self.use_max_params.as_ref() + if let Some(rule) = self.use_find.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[46])); } - if let Some(rule) = self.use_qwik_method_usage.as_ref() + if let Some(rule) = self.use_max_params.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[47])); } - if let Some(rule) = self.use_qwik_valid_lexical_scope.as_ref() + if let Some(rule) = self.use_qwik_method_usage.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[48])); } - if let Some(rule) = self.use_regexp_exec.as_ref() + if let Some(rule) = self.use_qwik_valid_lexical_scope.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[49])); } - if let Some(rule) = self.use_required_scripts.as_ref() + if let Some(rule) = self.use_regexp_exec.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[50])); } - if let Some(rule) = self.use_sorted_classes.as_ref() + if let Some(rule) = self.use_required_scripts.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[51])); } - if let Some(rule) = self.use_spread.as_ref() + if let Some(rule) = self.use_sorted_classes.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[52])); } - if let Some(rule) = self.use_unique_graphql_operation_name.as_ref() + if let Some(rule) = self.use_spread.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[53])); } - if let Some(rule) = self.use_vue_consistent_define_props_declaration.as_ref() + if let Some(rule) = self.use_unique_graphql_operation_name.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[54])); } - if let Some(rule) = self.use_vue_define_macros_order.as_ref() + if let Some(rule) = self.use_vue_consistent_define_props_declaration.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[55])); } - if let Some(rule) = self.use_vue_hyphenated_attributes.as_ref() + if let Some(rule) = self.use_vue_define_macros_order.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[56])); } - if let Some(rule) = self.use_vue_multi_word_component_names.as_ref() + if let Some(rule) = self.use_vue_hyphenated_attributes.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[57])); } - if let Some(rule) = self.use_vue_valid_v_bind.as_ref() + if let Some(rule) = self.use_vue_multi_word_component_names.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[58])); } - if let Some(rule) = self.use_vue_valid_v_else.as_ref() + if let Some(rule) = self.use_vue_valid_v_bind.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[59])); } - if let Some(rule) = self.use_vue_valid_v_else_if.as_ref() + if let Some(rule) = self.use_vue_valid_v_else.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[60])); } - if let Some(rule) = self.use_vue_valid_v_html.as_ref() + if let Some(rule) = self.use_vue_valid_v_else_if.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[61])); } - if let Some(rule) = self.use_vue_valid_v_if.as_ref() + if let Some(rule) = self.use_vue_valid_v_html.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[62])); } - if let Some(rule) = self.use_vue_valid_v_on.as_ref() + if let Some(rule) = self.use_vue_valid_v_if.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[63])); } - if let Some(rule) = self.use_vue_valid_v_text.as_ref() + if let Some(rule) = self.use_vue_valid_v_on.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[64])); } + if let Some(rule) = self.use_vue_valid_v_text.as_ref() + && rule.is_enabled() + { + index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[65])); + } index_set } fn get_disabled_rules(&self) -> FxHashSet> { @@ -5425,231 +5436,236 @@ impl RuleGroupExt for Nursery { { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[19])); } - if let Some(rule) = self.no_script_url.as_ref() + if let Some(rule) = self.no_return_assign.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[20])); } - if let Some(rule) = self.no_shadow.as_ref() + if let Some(rule) = self.no_script_url.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[21])); } - if let Some(rule) = self.no_sync_scripts.as_ref() + if let Some(rule) = self.no_shadow.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[22])); } - if let Some(rule) = self.no_ternary.as_ref() + if let Some(rule) = self.no_sync_scripts.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[23])); } - if let Some(rule) = self.no_undeclared_env_vars.as_ref() + if let Some(rule) = self.no_ternary.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[24])); } - if let Some(rule) = self.no_unknown_attribute.as_ref() + if let Some(rule) = self.no_undeclared_env_vars.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[25])); } - if let Some(rule) = self.no_unnecessary_conditions.as_ref() + if let Some(rule) = self.no_unknown_attribute.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[26])); } - if let Some(rule) = self.no_unresolved_imports.as_ref() + if let Some(rule) = self.no_unnecessary_conditions.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[27])); } - if let Some(rule) = self.no_unused_expressions.as_ref() + if let Some(rule) = self.no_unresolved_imports.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[28])); } - if let Some(rule) = self.no_useless_catch_binding.as_ref() + if let Some(rule) = self.no_unused_expressions.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[29])); } - if let Some(rule) = self.no_useless_undefined.as_ref() + if let Some(rule) = self.no_useless_catch_binding.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[30])); } - if let Some(rule) = self.no_vue_data_object_declaration.as_ref() + if let Some(rule) = self.no_useless_undefined.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[31])); } - if let Some(rule) = self.no_vue_duplicate_keys.as_ref() + if let Some(rule) = self.no_vue_data_object_declaration.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[32])); } - if let Some(rule) = self.no_vue_reserved_keys.as_ref() + if let Some(rule) = self.no_vue_duplicate_keys.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[33])); } - if let Some(rule) = self.no_vue_reserved_props.as_ref() + if let Some(rule) = self.no_vue_reserved_keys.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[34])); } - if let Some(rule) = self.no_vue_setup_props_reactivity_loss.as_ref() + if let Some(rule) = self.no_vue_reserved_props.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[35])); } - if let Some(rule) = self.no_vue_v_if_with_v_for.as_ref() + if let Some(rule) = self.no_vue_setup_props_reactivity_loss.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[36])); } - if let Some(rule) = self.use_array_sort_compare.as_ref() + if let Some(rule) = self.no_vue_v_if_with_v_for.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[37])); } - if let Some(rule) = self.use_await_thenable.as_ref() + if let Some(rule) = self.use_array_sort_compare.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[38])); } - if let Some(rule) = self.use_consistent_arrow_return.as_ref() + if let Some(rule) = self.use_await_thenable.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[39])); } - if let Some(rule) = self.use_consistent_graphql_descriptions.as_ref() + if let Some(rule) = self.use_consistent_arrow_return.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[40])); } - if let Some(rule) = self.use_deprecated_date.as_ref() + if let Some(rule) = self.use_consistent_graphql_descriptions.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[41])); } - if let Some(rule) = self.use_destructuring.as_ref() + if let Some(rule) = self.use_deprecated_date.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[42])); } - if let Some(rule) = self.use_exhaustive_switch_cases.as_ref() + if let Some(rule) = self.use_destructuring.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[43])); } - if let Some(rule) = self.use_explicit_type.as_ref() + if let Some(rule) = self.use_exhaustive_switch_cases.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[44])); } - if let Some(rule) = self.use_find.as_ref() + if let Some(rule) = self.use_explicit_type.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[45])); } - if let Some(rule) = self.use_max_params.as_ref() + if let Some(rule) = self.use_find.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[46])); } - if let Some(rule) = self.use_qwik_method_usage.as_ref() + if let Some(rule) = self.use_max_params.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[47])); } - if let Some(rule) = self.use_qwik_valid_lexical_scope.as_ref() + if let Some(rule) = self.use_qwik_method_usage.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[48])); } - if let Some(rule) = self.use_regexp_exec.as_ref() + if let Some(rule) = self.use_qwik_valid_lexical_scope.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[49])); } - if let Some(rule) = self.use_required_scripts.as_ref() + if let Some(rule) = self.use_regexp_exec.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[50])); } - if let Some(rule) = self.use_sorted_classes.as_ref() + if let Some(rule) = self.use_required_scripts.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[51])); } - if let Some(rule) = self.use_spread.as_ref() + if let Some(rule) = self.use_sorted_classes.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[52])); } - if let Some(rule) = self.use_unique_graphql_operation_name.as_ref() + if let Some(rule) = self.use_spread.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[53])); } - if let Some(rule) = self.use_vue_consistent_define_props_declaration.as_ref() + if let Some(rule) = self.use_unique_graphql_operation_name.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[54])); } - if let Some(rule) = self.use_vue_define_macros_order.as_ref() + if let Some(rule) = self.use_vue_consistent_define_props_declaration.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[55])); } - if let Some(rule) = self.use_vue_hyphenated_attributes.as_ref() + if let Some(rule) = self.use_vue_define_macros_order.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[56])); } - if let Some(rule) = self.use_vue_multi_word_component_names.as_ref() + if let Some(rule) = self.use_vue_hyphenated_attributes.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[57])); } - if let Some(rule) = self.use_vue_valid_v_bind.as_ref() + if let Some(rule) = self.use_vue_multi_word_component_names.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[58])); } - if let Some(rule) = self.use_vue_valid_v_else.as_ref() + if let Some(rule) = self.use_vue_valid_v_bind.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[59])); } - if let Some(rule) = self.use_vue_valid_v_else_if.as_ref() + if let Some(rule) = self.use_vue_valid_v_else.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[60])); } - if let Some(rule) = self.use_vue_valid_v_html.as_ref() + if let Some(rule) = self.use_vue_valid_v_else_if.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[61])); } - if let Some(rule) = self.use_vue_valid_v_if.as_ref() + if let Some(rule) = self.use_vue_valid_v_html.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[62])); } - if let Some(rule) = self.use_vue_valid_v_on.as_ref() + if let Some(rule) = self.use_vue_valid_v_if.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[63])); } - if let Some(rule) = self.use_vue_valid_v_text.as_ref() + if let Some(rule) = self.use_vue_valid_v_on.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[64])); } + if let Some(rule) = self.use_vue_valid_v_text.as_ref() + && rule.is_disabled() + { + index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[65])); + } index_set } #[doc = r" Checks if, given a rule name, matches one of the rules contained in this category"] @@ -5760,6 +5776,10 @@ impl RuleGroupExt for Nursery { .no_react_forward_ref .as_ref() .map(|conf| (conf.level(), conf.get_options())), + "noReturnAssign" => self + .no_return_assign + .as_ref() + .map(|conf| (conf.level(), conf.get_options())), "noScriptUrl" => self .no_script_url .as_ref() @@ -5968,6 +5988,7 @@ impl From for Nursery { no_parameters_only_used_in_recursion: Some(value.into()), no_proto: Some(value.into()), no_react_forward_ref: Some(value.into()), + no_return_assign: Some(value.into()), no_script_url: Some(value.into()), no_shadow: Some(value.into()), no_sync_scripts: Some(value.into()), diff --git a/crates/biome_diagnostics_categories/src/categories.rs b/crates/biome_diagnostics_categories/src/categories.rs index 5ff16e9abd66..3f54e392bd88 100644 --- a/crates/biome_diagnostics_categories/src/categories.rs +++ b/crates/biome_diagnostics_categories/src/categories.rs @@ -188,6 +188,7 @@ define_categories! { "lint/nursery/noProto": "https://biomejs.dev/linter/rules/no-proto", "lint/nursery/noReactForwardRef": "https://biomejs.dev/linter/rules/no-react-forward-ref", "lint/nursery/noScriptUrl": "https://biomejs.dev/linter/rules/no-script-url", + "lint/nursery/noReturnAssign": "https://biomejs.dev/linter/rules/no-return-assign", "lint/nursery/noShadow": "https://biomejs.dev/linter/rules/no-shadow", "lint/nursery/noSyncScripts": "https://biomejs.dev/linter/rules/no-sync-scripts", "lint/nursery/noTernary": "https://biomejs.dev/linter/rules/no-ternary", diff --git a/crates/biome_js_analyze/src/lint/nursery.rs b/crates/biome_js_analyze/src/lint/nursery.rs index fcc7d2e63bff..4f54d37dd96f 100644 --- a/crates/biome_js_analyze/src/lint/nursery.rs +++ b/crates/biome_js_analyze/src/lint/nursery.rs @@ -22,6 +22,7 @@ pub mod no_next_async_client_component; pub mod no_parameters_only_used_in_recursion; pub mod no_proto; pub mod no_react_forward_ref; +pub mod no_return_assign; pub mod no_script_url; pub mod no_shadow; pub mod no_sync_scripts; @@ -54,4 +55,4 @@ pub mod use_spread; pub mod use_vue_consistent_define_props_declaration; pub mod use_vue_define_macros_order; pub mod use_vue_multi_word_component_names; -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_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 ,] } } +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 ,] } } diff --git a/crates/biome_js_analyze/src/lint/nursery/no_return_assign.rs b/crates/biome_js_analyze/src/lint/nursery/no_return_assign.rs new file mode 100644 index 000000000000..9d32c1ca3951 --- /dev/null +++ b/crates/biome_js_analyze/src/lint/nursery/no_return_assign.rs @@ -0,0 +1,125 @@ +use biome_analyze::{ + QueryMatch, Rule, RuleDiagnostic, RuleSource, context::RuleContext, declare_lint_rule, +}; +use biome_console::markup; +use biome_diagnostics::Severity; +use biome_js_syntax::{ + AnyJsExpression, JsArrowFunctionExpression, JsAssignmentExpression, JsClassExpression, + JsFunctionExpression, JsReturnStatement, +}; +use biome_rowan::{AstNode, TextRange, WalkEvent, declare_node_union}; +use biome_rule_options::no_return_assign::NoReturnAssignOptions; + +use crate::services::semantic::Semantic; + +declare_lint_rule! { + /// Disallow assignments in return statements. + /// + /// In return statements, it is common to mistype a comparison operator (such as `==`) as an assignment operator (such as `=`). + /// Moreover, the use of assignments in a return statement is confusing. + /// Return statements are often considered side-effect free. + /// + /// ## Examples + /// + /// ### Invalid + /// + /// ```js,expect_diagnostic + /// function f(a) { + /// return a = 1; + /// } + /// ``` + /// + /// ### Valid + /// + /// ```js + /// function f(a) { + /// a = 1; + /// return a; + /// } + /// ``` + /// + /// ```js + /// function f(a) { + /// return a == 1; + /// } + /// ``` + /// + pub NoReturnAssign { + version: "next", + name: "noReturnAssign", + language: "js", + sources: &[RuleSource::Eslint("no-return-assign").same()], + recommended: false, + severity: Severity::Error, + } +} + +declare_node_union! { + pub AnyReturn = JsReturnStatement | JsArrowFunctionExpression +} + +impl Rule for NoReturnAssign { + type Query = Semantic; + type State = TextRange; + type Signals = Vec; + type Options = NoReturnAssignOptions; + + fn run(ctx: &RuleContext) -> Self::Signals { + run_options(ctx).unwrap_or_default() + } + + fn diagnostic(_ctx: &RuleContext, state: &Self::State) -> Option { + Some( + RuleDiagnostic::new( + rule_category!(), + state, + markup!{ + "Return statements"" should not contain ""assignments""." + }, + ).note(markup! { + "Assignments inside return statements are easy to mistake for comparison operators (`==`), " + "and add unexpected side effects to normally-pure code." + "\nIf the assignment is intentional, move it outside of the return statement." + })) + } +} + +fn run_options(ctx: &RuleContext) -> Option> { + match ctx.query() { + AnyReturn::JsReturnStatement(query) => Some(traverse_expression(&query.argument()?)), + + AnyReturn::JsArrowFunctionExpression(query) => Some(traverse_expression( + query.body().ok()?.as_any_js_expression()?, + )), + } +} + +fn traverse_expression(root: &AnyJsExpression) -> Vec { + let mut signal = Vec::new(); + let mut iter = root.syntax().preorder(); + + while let Some(event) = iter.next() { + if let WalkEvent::Enter(node) = event { + if JsAssignmentExpression::can_cast(node.kind()) { + signal.push(node.text_range()); + } + + // Skip function and class boundaries - assignments inside nested + // functions/classes are not part of this return statement + if JsArrowFunctionExpression::can_cast(node.kind()) + || JsFunctionExpression::can_cast(node.kind()) + || JsClassExpression::can_cast(node.kind()) + { + iter.skip_subtree(); + continue; + } + + let is_expression = AnyJsExpression::can_cast(node.kind()); + + if !is_expression { + iter.skip_subtree(); + } + } + } + signal +} diff --git a/crates/biome_js_analyze/tests/specs/nursery/noReturnAssign/invalid.js b/crates/biome_js_analyze/tests/specs/nursery/noReturnAssign/invalid.js new file mode 100644 index 000000000000..c6b4fd73bcce --- /dev/null +++ b/crates/biome_js_analyze/tests/specs/nursery/noReturnAssign/invalid.js @@ -0,0 +1,110 @@ +/* should generate diagnostics */ + +const f = (a) => a = 1; + +function f(a) { + return a = 1; +} + +function f(a) { + return (a = 1); +} + +function f(a, b, c) { + return (a, b, c = 1); +} + +function f(a, b, c) { + return a == (b = c); +} +function f(a, b) { + return a && (b = 1); +} + +function f(a, b, c) { + return a = (b = c); +} + +function f(a, b, c) { + return (a = 1, b = 2, c = 3); +} + +function f(a) { + return [a = 1]; +} + +async function f(a) { + return await (a = 1); +} + +function f(a) { + return 5 + (a = 1); +} + +function f(a) { + return (a = 1) + 5; +} + +function f(a) { + return foo(a = 1); +} + +function f(a, b) { + return b[a = 1]; +} + +function f(a) { + return (a = 1) ? true : false; +} + +function f(a) { + return true ? a = 1 : false; +} + +function f(a, b) { + return true ? false : a = 1; +} + +function f(a, b) { + return (a = 1) in b; +} + +function f(a, Class) { + return (a = 1) instanceof Class; +} + +function f(a, b) { + return (a = 1) || b; +} + +function f(a, b) { + return a || (b = 1); +} + +function f(a, b) { + return (a = 1) ?? b; +} + +function f(a, b) { + return a ?? (b = 1); +} + +function f(a) { + return !(a = 1); +} + +function f(a) { + return typeof (a = 1); +} + +function f(a) { + return void (a = 1); +} + +function f(a) { + return -(a = 1); +} + +function f(a) { + return
; +} diff --git a/crates/biome_js_analyze/tests/specs/nursery/noReturnAssign/invalid.js.snap b/crates/biome_js_analyze/tests/specs/nursery/noReturnAssign/invalid.js.snap new file mode 100644 index 000000000000..8fd5c659f9da --- /dev/null +++ b/crates/biome_js_analyze/tests/specs/nursery/noReturnAssign/invalid.js.snap @@ -0,0 +1,674 @@ +--- +source: crates/biome_js_analyze/tests/spec_tests.rs +expression: invalid.js +--- +# Input +```js +/* should generate diagnostics */ + +const f = (a) => a = 1; + +function f(a) { + return a = 1; +} + +function f(a) { + return (a = 1); +} + +function f(a, b, c) { + return (a, b, c = 1); +} + +function f(a, b, c) { + return a == (b = c); +} +function f(a, b) { + return a && (b = 1); +} + +function f(a, b, c) { + return a = (b = c); +} + +function f(a, b, c) { + return (a = 1, b = 2, c = 3); +} + +function f(a) { + return [a = 1]; +} + +async function f(a) { + return await (a = 1); +} + +function f(a) { + return 5 + (a = 1); +} + +function f(a) { + return (a = 1) + 5; +} + +function f(a) { + return foo(a = 1); +} + +function f(a, b) { + return b[a = 1]; +} + +function f(a) { + return (a = 1) ? true : false; +} + +function f(a) { + return true ? a = 1 : false; +} + +function f(a, b) { + return true ? false : a = 1; +} + +function f(a, b) { + return (a = 1) in b; +} + +function f(a, Class) { + return (a = 1) instanceof Class; +} + +function f(a, b) { + return (a = 1) || b; +} + +function f(a, b) { + return a || (b = 1); +} + +function f(a, b) { + return (a = 1) ?? b; +} + +function f(a, b) { + return a ?? (b = 1); +} + +function f(a) { + return !(a = 1); +} + +function f(a) { + return typeof (a = 1); +} + +function f(a) { + return void (a = 1); +} + +function f(a) { + return -(a = 1); +} + +function f(a) { + return
; +} + +``` + +_Note: The parser emitted 4 diagnostics which are not shown here._ + +# Diagnostics +``` +invalid.js:3:18 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 1 │ /* should generate diagnostics */ + 2 │ + > 3 │ const f = (a) => a = 1; + │ ^^^^^ + 4 │ + 5 │ function f(a) { + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:6:9 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 5 │ function f(a) { + > 6 │ return a = 1; + │ ^^^^^ + 7 │ } + 8 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:10:10 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 9 │ function f(a) { + > 10 │ return (a = 1); + │ ^^^^^ + 11 │ } + 12 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:14:16 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 13 │ function f(a, b, c) { + > 14 │ return (a, b, c = 1); + │ ^^^^^ + 15 │ } + 16 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:18:15 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 17 │ function f(a, b, c) { + > 18 │ return a == (b = c); + │ ^^^^^ + 19 │ } + 20 │ function f(a, b) { + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:21:15 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 19 │ } + 20 │ function f(a, b) { + > 21 │ return a && (b = 1); + │ ^^^^^ + 22 │ } + 23 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:25:9 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 24 │ function f(a, b, c) { + > 25 │ return a = (b = c); + │ ^^^^^^^^^^^ + 26 │ } + 27 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:25:14 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 24 │ function f(a, b, c) { + > 25 │ return a = (b = c); + │ ^^^^^ + 26 │ } + 27 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:29:10 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 28 │ function f(a, b, c) { + > 29 │ return (a = 1, b = 2, c = 3); + │ ^^^^^ + 30 │ } + 31 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:29:17 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 28 │ function f(a, b, c) { + > 29 │ return (a = 1, b = 2, c = 3); + │ ^^^^^ + 30 │ } + 31 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:29:24 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 28 │ function f(a, b, c) { + > 29 │ return (a = 1, b = 2, c = 3); + │ ^^^^^ + 30 │ } + 31 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:37:16 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 36 │ async function f(a) { + > 37 │ return await (a = 1); + │ ^^^^^ + 38 │ } + 39 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:41:14 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 40 │ function f(a) { + > 41 │ return 5 + (a = 1); + │ ^^^^^ + 42 │ } + 43 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:45:10 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 44 │ function f(a) { + > 45 │ return (a = 1) + 5; + │ ^^^^^ + 46 │ } + 47 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:53:11 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 52 │ function f(a, b) { + > 53 │ return b[a = 1]; + │ ^^^^^ + 54 │ } + 55 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:57:10 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 56 │ function f(a) { + > 57 │ return (a = 1) ? true : false; + │ ^^^^^ + 58 │ } + 59 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:61:16 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 60 │ function f(a) { + > 61 │ return true ? a = 1 : false; + │ ^^^^^ + 62 │ } + 63 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:65:24 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 64 │ function f(a, b) { + > 65 │ return true ? false : a = 1; + │ ^^^^^ + 66 │ } + 67 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:69:10 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 68 │ function f(a, b) { + > 69 │ return (a = 1) in b; + │ ^^^^^ + 70 │ } + 71 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:73:10 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 72 │ function f(a, Class) { + > 73 │ return (a = 1) instanceof Class; + │ ^^^^^ + 74 │ } + 75 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:77:10 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 76 │ function f(a, b) { + > 77 │ return (a = 1) || b; + │ ^^^^^ + 78 │ } + 79 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:81:15 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 80 │ function f(a, b) { + > 81 │ return a || (b = 1); + │ ^^^^^ + 82 │ } + 83 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:85:10 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 84 │ function f(a, b) { + > 85 │ return (a = 1) ?? b; + │ ^^^^^ + 86 │ } + 87 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:89:15 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 88 │ function f(a, b) { + > 89 │ return a ?? (b = 1); + │ ^^^^^ + 90 │ } + 91 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:93:11 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 92 │ function f(a) { + > 93 │ return !(a = 1); + │ ^^^^^ + 94 │ } + 95 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:97:17 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 96 │ function f(a) { + > 97 │ return typeof (a = 1); + │ ^^^^^ + 98 │ } + 99 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:101:15 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 100 │ function f(a) { + > 101 │ return void (a = 1); + │ ^^^^^ + 102 │ } + 103 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:105:11 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 104 │ function f(a) { + > 105 │ return -(a = 1); + │ ^^^^^ + 106 │ } + 107 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.js:109:9 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 108 │ function f(a) { + > 109 │ return
; + │ ^^^^^^^^^^^^^^^^^^^^ + 110 │ } + 111 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` diff --git a/crates/biome_js_analyze/tests/specs/nursery/noReturnAssign/invalid.ts b/crates/biome_js_analyze/tests/specs/nursery/noReturnAssign/invalid.ts new file mode 100644 index 000000000000..7a233c2c58f3 --- /dev/null +++ b/crates/biome_js_analyze/tests/specs/nursery/noReturnAssign/invalid.ts @@ -0,0 +1,16 @@ +/* should generate diagnostics */ +function f(a) { + return (a = 1) as number; +} + +function f(a) { + return (a = 1)!; +} + +function f(a) { + return (a = 1) satisfies number; +} + +function f(a) { + return (a = 1); +} diff --git a/crates/biome_js_analyze/tests/specs/nursery/noReturnAssign/invalid.ts.snap b/crates/biome_js_analyze/tests/specs/nursery/noReturnAssign/invalid.ts.snap new file mode 100644 index 000000000000..b59dbdc61690 --- /dev/null +++ b/crates/biome_js_analyze/tests/specs/nursery/noReturnAssign/invalid.ts.snap @@ -0,0 +1,102 @@ +--- +source: crates/biome_js_analyze/tests/spec_tests.rs +expression: invalid.ts +--- +# Input +```ts +/* should generate diagnostics */ +function f(a) { + return (a = 1) as number; +} + +function f(a) { + return (a = 1)!; +} + +function f(a) { + return (a = 1) satisfies number; +} + +function f(a) { + return (a = 1); +} + +``` + +# Diagnostics +``` +invalid.ts:3:10 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 1 │ /* should generate diagnostics */ + 2 │ function f(a) { + > 3 │ return (a = 1) as number; + │ ^^^^^ + 4 │ } + 5 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.ts:7:10 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 6 │ function f(a) { + > 7 │ return (a = 1)!; + │ ^^^^^ + 8 │ } + 9 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.ts:11:10 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 10 │ function f(a) { + > 11 │ return (a = 1) satisfies number; + │ ^^^^^ + 12 │ } + 13 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` + +``` +invalid.ts:15:18 lint/nursery/noReturnAssign ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + × Return statements should not contain assignments. + + 14 │ function f(a) { + > 15 │ return (a = 1); + │ ^^^^^ + 16 │ } + 17 │ + + i Assignments inside return statements are easy to mistake for comparison operators (`==`), and add unexpected side effects to normally-pure code. + If the assignment is intentional, move it outside of the return statement. + + i This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information. + + +``` diff --git a/crates/biome_js_analyze/tests/specs/nursery/noReturnAssign/valid.js b/crates/biome_js_analyze/tests/specs/nursery/noReturnAssign/valid.js new file mode 100644 index 000000000000..a68d551cf6c4 --- /dev/null +++ b/crates/biome_js_analyze/tests/specs/nursery/noReturnAssign/valid.js @@ -0,0 +1,26 @@ +/* should not generate diagnostics */ +function f(a) { + return a == 1; +} +function f1(a) { + a = 1; + return a; +} + +function f(a) { + return (a == 1); +} + +function f(a, b, c) { + return (a == 1, b, c); +} + +function f(a, b, c) { + return a == (b == c); +} +function f(a, b, c) { + return a ? b == 1 : c; +} +function f(a, b) { + return a && (b == 1); +} diff --git a/crates/biome_js_analyze/tests/specs/nursery/noReturnAssign/valid.js.snap b/crates/biome_js_analyze/tests/specs/nursery/noReturnAssign/valid.js.snap new file mode 100644 index 000000000000..f121bf9f8cb1 --- /dev/null +++ b/crates/biome_js_analyze/tests/specs/nursery/noReturnAssign/valid.js.snap @@ -0,0 +1,34 @@ +--- +source: crates/biome_js_analyze/tests/spec_tests.rs +expression: valid.js +--- +# Input +```js +/* should not generate diagnostics */ +function f(a) { + return a == 1; +} +function f1(a) { + a = 1; + return a; +} + +function f(a) { + return (a == 1); +} + +function f(a, b, c) { + return (a == 1, b, c); +} + +function f(a, b, c) { + return a == (b == c); +} +function f(a, b, c) { + return a ? b == 1 : c; +} +function f(a, b) { + return a && (b == 1); +} + +``` diff --git a/crates/biome_rule_options/src/lib.rs b/crates/biome_rule_options/src/lib.rs index a80a37dc1081..8e6a2a58b396 100644 --- a/crates/biome_rule_options/src/lib.rs +++ b/crates/biome_rule_options/src/lib.rs @@ -172,6 +172,7 @@ pub mod no_restricted_elements; pub mod no_restricted_globals; pub mod no_restricted_imports; pub mod no_restricted_types; +pub mod no_return_assign; pub mod no_script_url; pub mod no_secrets; pub mod no_self_assign; diff --git a/crates/biome_rule_options/src/no_return_assign.rs b/crates/biome_rule_options/src/no_return_assign.rs new file mode 100644 index 000000000000..c7ec54545c4e --- /dev/null +++ b/crates/biome_rule_options/src/no_return_assign.rs @@ -0,0 +1,6 @@ +use biome_deserialize_macros::{Deserializable, Merge}; +use serde::{Deserialize, Serialize}; +#[derive(Default, Clone, Debug, Deserialize, Deserializable, Merge, Eq, PartialEq, Serialize)] +#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] +#[serde(rename_all = "camelCase", deny_unknown_fields, default)] +pub struct NoReturnAssignOptions {} diff --git a/packages/@biomejs/backend-jsonrpc/src/workspace.ts b/packages/@biomejs/backend-jsonrpc/src/workspace.ts index 1836a69b1abb..6709069aa256 100644 --- a/packages/@biomejs/backend-jsonrpc/src/workspace.ts +++ b/packages/@biomejs/backend-jsonrpc/src/workspace.ts @@ -1958,6 +1958,11 @@ See */ noReactForwardRef?: NoReactForwardRefConfiguration; /** + * Disallow assignments in return statements. +See + */ + noReturnAssign?: NoReturnAssignConfiguration; + /** * Disallow javascript: URLs in HTML. See */ @@ -3670,6 +3675,9 @@ export type NoProtoConfiguration = export type NoReactForwardRefConfiguration = | RulePlainConfiguration | RuleWithNoReactForwardRefOptions; +export type NoReturnAssignConfiguration = + | RulePlainConfiguration + | RuleWithNoReturnAssignOptions; export type NoScriptUrlConfiguration = | RulePlainConfiguration | RuleWithNoScriptUrlOptions; @@ -5117,6 +5125,10 @@ export interface RuleWithNoReactForwardRefOptions { level: RulePlainConfiguration; options?: NoReactForwardRefOptions; } +export interface RuleWithNoReturnAssignOptions { + level: RulePlainConfiguration; + options?: NoReturnAssignOptions; +} export interface RuleWithNoScriptUrlOptions { level: RulePlainConfiguration; options?: NoScriptUrlOptions; @@ -6457,6 +6469,7 @@ export type NoNextAsyncClientComponentOptions = {}; export type NoParametersOnlyUsedInRecursionOptions = {}; export type NoProtoOptions = {}; export type NoReactForwardRefOptions = {}; +export type NoReturnAssignOptions = {}; export type NoScriptUrlOptions = {}; export type NoShadowOptions = {}; export type NoSyncScriptsOptions = {}; @@ -7320,6 +7333,7 @@ export type Category = | "lint/nursery/noProto" | "lint/nursery/noReactForwardRef" | "lint/nursery/noScriptUrl" + | "lint/nursery/noReturnAssign" | "lint/nursery/noShadow" | "lint/nursery/noSyncScripts" | "lint/nursery/noTernary" diff --git a/packages/@biomejs/biome/configuration_schema.json b/packages/@biomejs/biome/configuration_schema.json index cfeaf99e5e51..0f9758885962 100644 --- a/packages/@biomejs/biome/configuration_schema.json +++ b/packages/@biomejs/biome/configuration_schema.json @@ -4244,6 +4244,16 @@ }, "additionalProperties": false }, + "NoReturnAssignConfiguration": { + "oneOf": [ + { "$ref": "#/$defs/RulePlainConfiguration" }, + { "$ref": "#/$defs/RuleWithNoReturnAssignOptions" } + ] + }, + "NoReturnAssignOptions": { + "type": "object", + "additionalProperties": false + }, "NoScriptUrlConfiguration": { "oneOf": [ { "$ref": "#/$defs/RulePlainConfiguration" }, @@ -5302,6 +5312,13 @@ { "type": "null" } ] }, + "noReturnAssign": { + "description": "Disallow assignments in return statements.\nSee ", + "anyOf": [ + { "$ref": "#/$defs/NoReturnAssignConfiguration" }, + { "type": "null" } + ] + }, "noScriptUrl": { "description": "Disallow javascript: URLs in HTML.\nSee ", "anyOf": [ @@ -7737,6 +7754,15 @@ "additionalProperties": false, "required": ["level"] }, + "RuleWithNoReturnAssignOptions": { + "type": "object", + "properties": { + "level": { "$ref": "#/$defs/RulePlainConfiguration" }, + "options": { "$ref": "#/$defs/NoReturnAssignOptions" } + }, + "additionalProperties": false, + "required": ["level"] + }, "RuleWithNoScriptUrlOptions": { "type": "object", "properties": {