diff --git a/.changeset/cold-ravens-show.md b/.changeset/cold-ravens-show.md new file mode 100644 index 000000000000..d5bb92c51854 --- /dev/null +++ b/.changeset/cold-ravens-show.md @@ -0,0 +1,13 @@ +--- +"@biomejs/biome": patch +--- + +Added the nursery rule [`useUniqueInputFieldNames`](https://biomejs.dev/linter/rules/use-unique-input-field-names/). Require fields within an input object to be unique. + +**Invalid:** + +```graphql +query A($x: Int, $x: Int) { + field +} +``` diff --git a/crates/biome_configuration/src/analyzer/linter/rules.rs b/crates/biome_configuration/src/analyzer/linter/rules.rs index 9d0c2e282def..eb1c3f3caa65 100644 --- a/crates/biome_configuration/src/analyzer/linter/rules.rs +++ b/crates/biome_configuration/src/analyzer/linter/rules.rs @@ -467,6 +467,7 @@ pub enum RuleName { UseUnifiedTypeSignatures, UseUniqueElementIds, UseUniqueGraphqlOperationName, + UseUniqueInputFieldNames, UseUniqueVariableNames, UseValidAnchor, UseValidAriaProps, @@ -875,6 +876,7 @@ impl RuleName { Self::UseUnifiedTypeSignatures => "useUnifiedTypeSignatures", Self::UseUniqueElementIds => "useUniqueElementIds", Self::UseUniqueGraphqlOperationName => "useUniqueGraphqlOperationName", + Self::UseUniqueInputFieldNames => "useUniqueInputFieldNames", Self::UseUniqueVariableNames => "useUniqueVariableNames", Self::UseValidAnchor => "useValidAnchor", Self::UseValidAriaProps => "useValidAriaProps", @@ -1281,6 +1283,7 @@ impl RuleName { Self::UseUnifiedTypeSignatures => RuleGroup::Style, Self::UseUniqueElementIds => RuleGroup::Correctness, Self::UseUniqueGraphqlOperationName => RuleGroup::Nursery, + Self::UseUniqueInputFieldNames => RuleGroup::Nursery, Self::UseUniqueVariableNames => RuleGroup::Nursery, Self::UseValidAnchor => RuleGroup::A11y, Self::UseValidAriaProps => RuleGroup::A11y, @@ -1694,6 +1697,7 @@ impl std::str::FromStr for RuleName { "useUnifiedTypeSignatures" => Ok(Self::UseUnifiedTypeSignatures), "useUniqueElementIds" => Ok(Self::UseUniqueElementIds), "useUniqueGraphqlOperationName" => Ok(Self::UseUniqueGraphqlOperationName), + "useUniqueInputFieldNames" => Ok(Self::UseUniqueInputFieldNames), "useUniqueVariableNames" => Ok(Self::UseUniqueVariableNames), "useValidAnchor" => Ok(Self::UseValidAnchor), "useValidAriaProps" => Ok(Self::UseValidAriaProps), @@ -4852,7 +4856,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 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 = "Require all variable definitions to be unique.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_unique_variable_names : Option < RuleConfiguration < biome_rule_options :: use_unique_variable_names :: UseUniqueVariableNamesOptions >> , # [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 = "Require fields within an input object to be unique.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_unique_input_field_names : Option < RuleConfiguration < biome_rule_options :: use_unique_input_field_names :: UseUniqueInputFieldNamesOptions >> , # [doc = "Require all variable definitions to be unique.\nSee "] # [serde (skip_serializing_if = "Option::is_none")] pub use_unique_variable_names : Option < RuleConfiguration < biome_rule_options :: use_unique_variable_names :: UseUniqueVariableNamesOptions >> , # [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] = &[ @@ -4911,6 +4915,7 @@ impl Nursery { "useSortedClasses", "useSpread", "useUniqueGraphqlOperationName", + "useUniqueInputFieldNames", "useUniqueVariableNames", "useVueConsistentDefinePropsDeclaration", "useVueDefineMacrosOrder", @@ -4997,6 +5002,7 @@ impl Nursery { RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[64]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[65]), RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[66]), + RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[67]), ]; } impl RuleGroupExt for Nursery { @@ -5283,66 +5289,71 @@ impl RuleGroupExt for Nursery { { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[54])); } - if let Some(rule) = self.use_unique_variable_names.as_ref() + if let Some(rule) = self.use_unique_input_field_names.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[55])); } - if let Some(rule) = self.use_vue_consistent_define_props_declaration.as_ref() + if let Some(rule) = self.use_unique_variable_names.as_ref() && rule.is_enabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[56])); } - 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[57])); } - 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[58])); } - 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[59])); } - 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[60])); } - 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[61])); } - 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[62])); } - 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[63])); } - 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[64])); } - 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[65])); } - 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[66])); } + 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[67])); + } index_set } fn get_disabled_rules(&self) -> FxHashSet> { @@ -5622,66 +5633,71 @@ impl RuleGroupExt for Nursery { { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[54])); } - if let Some(rule) = self.use_unique_variable_names.as_ref() + if let Some(rule) = self.use_unique_input_field_names.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[55])); } - if let Some(rule) = self.use_vue_consistent_define_props_declaration.as_ref() + if let Some(rule) = self.use_unique_variable_names.as_ref() && rule.is_disabled() { index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[56])); } - 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[57])); } - 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[58])); } - 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[59])); } - 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[60])); } - 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[61])); } - 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[62])); } - 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[63])); } - 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[64])); } - 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[65])); } - 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[66])); } + 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[67])); + } index_set } #[doc = r" Checks if, given a rule name, matches one of the rules contained in this category"] @@ -5932,6 +5948,10 @@ impl RuleGroupExt for Nursery { .use_unique_graphql_operation_name .as_ref() .map(|conf| (conf.level(), conf.get_options())), + "useUniqueInputFieldNames" => self + .use_unique_input_field_names + .as_ref() + .map(|conf| (conf.level(), conf.get_options())), "useUniqueVariableNames" => self .use_unique_variable_names .as_ref() @@ -6043,6 +6063,7 @@ impl From for Nursery { use_sorted_classes: Some(value.into()), use_spread: Some(value.into()), use_unique_graphql_operation_name: Some(value.into()), + use_unique_input_field_names: Some(value.into()), use_unique_variable_names: Some(value.into()), use_vue_consistent_define_props_declaration: Some(value.into()), use_vue_define_macros_order: Some(value.into()), diff --git a/crates/biome_diagnostics_categories/src/categories.rs b/crates/biome_diagnostics_categories/src/categories.rs index 5885df765942..2ca95cbd99f5 100644 --- a/crates/biome_diagnostics_categories/src/categories.rs +++ b/crates/biome_diagnostics_categories/src/categories.rs @@ -230,6 +230,7 @@ define_categories! { "lint/nursery/useSortedClasses": "https://biomejs.dev/linter/rules/use-sorted-classes", "lint/nursery/useSpread": "https://biomejs.dev/linter/rules/no-spread", "lint/nursery/useUniqueGraphqlOperationName": "https://biomejs.dev/linter/rules/use-unique-graphql-operation-name", + "lint/nursery/useUniqueInputFieldNames": "https://biomejs.dev/linter/rules/use-unique-input-field-names", "lint/nursery/useUniqueVariableNames": "https://biomejs.dev/linter/rules/use-unique-variable-names", "lint/nursery/useVueConsistentDefinePropsDeclaration": "https://biomejs.dev/linter/rules/use-vue-consistent-define-props-declaration", "lint/nursery/useVueDefineMacrosOrder": "https://biomejs.dev/linter/rules/use-vue-define-macros-order", diff --git a/crates/biome_graphql_analyze/src/lint/nursery.rs b/crates/biome_graphql_analyze/src/lint/nursery.rs index 76faa01402b3..d05db2447549 100644 --- a/crates/biome_graphql_analyze/src/lint/nursery.rs +++ b/crates/biome_graphql_analyze/src/lint/nursery.rs @@ -7,5 +7,6 @@ pub mod no_empty_source; pub mod use_consistent_graphql_descriptions; pub mod use_deprecated_date; pub mod use_unique_graphql_operation_name; +pub mod use_unique_input_field_names; pub mod use_unique_variable_names; -declare_lint_group! { pub Nursery { name : "nursery" , rules : [self :: no_empty_source :: NoEmptySource , self :: use_consistent_graphql_descriptions :: UseConsistentGraphqlDescriptions , self :: use_deprecated_date :: UseDeprecatedDate , self :: use_unique_graphql_operation_name :: UseUniqueGraphqlOperationName , self :: use_unique_variable_names :: UseUniqueVariableNames ,] } } +declare_lint_group! { pub Nursery { name : "nursery" , rules : [self :: no_empty_source :: NoEmptySource , self :: use_consistent_graphql_descriptions :: UseConsistentGraphqlDescriptions , self :: use_deprecated_date :: UseDeprecatedDate , self :: use_unique_graphql_operation_name :: UseUniqueGraphqlOperationName , self :: use_unique_input_field_names :: UseUniqueInputFieldNames , self :: use_unique_variable_names :: UseUniqueVariableNames ,] } } diff --git a/crates/biome_graphql_analyze/src/lint/nursery/use_unique_input_field_names.rs b/crates/biome_graphql_analyze/src/lint/nursery/use_unique_input_field_names.rs new file mode 100644 index 000000000000..49eac9f5a685 --- /dev/null +++ b/crates/biome_graphql_analyze/src/lint/nursery/use_unique_input_field_names.rs @@ -0,0 +1,84 @@ +use std::collections::HashSet; + +use biome_analyze::{ + Ast, Rule, RuleDiagnostic, RuleSource, context::RuleContext, declare_lint_rule, +}; +use biome_console::markup; +use biome_graphql_syntax::GraphqlObjectValue; +use biome_rowan::{AstNode, TokenText}; +use biome_rule_options::use_unique_input_field_names::UseUniqueInputFieldNamesOptions; + +declare_lint_rule! { + /// Require fields within an input object to be unique. + /// + /// A GraphQL input object value is only valid if all supplied fields are uniquely named. + /// + /// ## Examples + /// + /// ### Invalid + /// + /// ```graphql,expect_diagnostic + /// query { + /// field(arg: { f1: "value", f1: "value" }) + /// } + /// ``` + /// + /// ### Valid + /// + /// ```graphql + /// query { + /// field(arg: { f1: "value", f2: "value" }) + /// } + /// ``` + /// + pub UseUniqueInputFieldNames { + version: "next", + name: "useUniqueInputFieldNames", + language: "graphql", + recommended: false, + sources: &[RuleSource::EslintGraphql("unique-input-field-names").same()], + } +} + +impl Rule for UseUniqueInputFieldNames { + type Query = Ast; + type State = (); + type Signals = Option; + type Options = UseUniqueInputFieldNamesOptions; + + fn run(ctx: &RuleContext) -> Self::Signals { + let node = ctx.query(); + let mut found: HashSet = HashSet::new(); + + for element in node.members() { + if let Some(name) = element.name().ok() + && let Some(value_token) = name.value_token().ok() + { + let string = value_token.token_text(); + if found.contains(&string) { + return Some(()); + } else { + found.insert(string); + } + } + } + + None + } + + fn diagnostic(ctx: &RuleContext, _state: &Self::State) -> Option { + let span = ctx.query().range(); + Some( + RuleDiagnostic::new( + rule_category!(), + span, + markup! { + "Duplicate input field name." + }, + ) + .note(markup! { + "A GraphQL input object value is only valid if all supplied fields are uniquely named. Make sure to name every input field differently." + }), + ) + } +} diff --git a/crates/biome_graphql_analyze/tests/specs/nursery/useUniqueInputFieldNames/invalid.graphql b/crates/biome_graphql_analyze/tests/specs/nursery/useUniqueInputFieldNames/invalid.graphql new file mode 100644 index 000000000000..e18eb6447df0 --- /dev/null +++ b/crates/biome_graphql_analyze/tests/specs/nursery/useUniqueInputFieldNames/invalid.graphql @@ -0,0 +1,10 @@ +# should generate diagnostics +query A { + field(arg: { f1: "value", f1: "value" }) +} +query B { + field(arg: { f1: "value", f1: "value", f1: "value" }) +} +query C { + field(arg: { f1: {f2: "value", f2: "value" }}) +} diff --git a/crates/biome_graphql_analyze/tests/specs/nursery/useUniqueInputFieldNames/invalid.graphql.snap b/crates/biome_graphql_analyze/tests/specs/nursery/useUniqueInputFieldNames/invalid.graphql.snap new file mode 100644 index 000000000000..d6b1e51bc2d1 --- /dev/null +++ b/crates/biome_graphql_analyze/tests/specs/nursery/useUniqueInputFieldNames/invalid.graphql.snap @@ -0,0 +1,76 @@ +--- +source: crates/biome_graphql_analyze/tests/spec_tests.rs +expression: invalid.graphql +--- +# Input +```graphql +# should generate diagnostics +query A { + field(arg: { f1: "value", f1: "value" }) +} +query B { + field(arg: { f1: "value", f1: "value", f1: "value" }) +} +query C { + field(arg: { f1: {f2: "value", f2: "value" }}) +} + +``` + +# Diagnostics +``` +invalid.graphql:3:13 lint/nursery/useUniqueInputFieldNames ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + i Duplicate input field name. + + 1 │ # should generate diagnostics + 2 │ query A { + > 3 │ field(arg: { f1: "value", f1: "value" }) + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 4 │ } + 5 │ query B { + + i A GraphQL input object value is only valid if all supplied fields are uniquely named. Make sure to name every input field differently. + + 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.graphql:6:13 lint/nursery/useUniqueInputFieldNames ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + i Duplicate input field name. + + 4 │ } + 5 │ query B { + > 6 │ field(arg: { f1: "value", f1: "value", f1: "value" }) + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 7 │ } + 8 │ query C { + + i A GraphQL input object value is only valid if all supplied fields are uniquely named. Make sure to name every input field differently. + + 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.graphql:9:19 lint/nursery/useUniqueInputFieldNames ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ + + i Duplicate input field name. + + 7 │ } + 8 │ query C { + > 9 │ field(arg: { f1: {f2: "value", f2: "value" }}) + │ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 10 │ } + 11 │ + + i A GraphQL input object value is only valid if all supplied fields are uniquely named. Make sure to name every input field differently. + + 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_graphql_analyze/tests/specs/nursery/useUniqueInputFieldNames/valid.graphql b/crates/biome_graphql_analyze/tests/specs/nursery/useUniqueInputFieldNames/valid.graphql new file mode 100644 index 000000000000..6d17ff4d4c9c --- /dev/null +++ b/crates/biome_graphql_analyze/tests/specs/nursery/useUniqueInputFieldNames/valid.graphql @@ -0,0 +1,21 @@ +# should not generate diagnostics +query A { + field(arg: { f: true }) +} +query B { + field(arg1: { f: true }, arg2: { f: true }) +} +query C { + field(arg: { f1: "value", f2: "value", f3: "value" }) +} +query D { + field(arg: { + deep: { + deep: { + id: 1 + } + id: 1 + } + id: 1 + }) +} diff --git a/crates/biome_graphql_analyze/tests/specs/nursery/useUniqueInputFieldNames/valid.graphql.snap b/crates/biome_graphql_analyze/tests/specs/nursery/useUniqueInputFieldNames/valid.graphql.snap new file mode 100644 index 000000000000..30c71f17b2bc --- /dev/null +++ b/crates/biome_graphql_analyze/tests/specs/nursery/useUniqueInputFieldNames/valid.graphql.snap @@ -0,0 +1,29 @@ +--- +source: crates/biome_graphql_analyze/tests/spec_tests.rs +expression: valid.graphql +--- +# Input +```graphql +# should not generate diagnostics +query A { + field(arg: { f: true }) +} +query B { + field(arg1: { f: true }, arg2: { f: true }) +} +query C { + field(arg: { f1: "value", f2: "value", f3: "value" }) +} +query D { + field(arg: { + deep: { + deep: { + id: 1 + } + id: 1 + } + id: 1 + }) +} + +``` diff --git a/crates/biome_rule_options/src/lib.rs b/crates/biome_rule_options/src/lib.rs index 2219e66dd592..733a8cfd1ba8 100644 --- a/crates/biome_rule_options/src/lib.rs +++ b/crates/biome_rule_options/src/lib.rs @@ -384,6 +384,7 @@ pub mod use_trim_start_end; pub mod use_unified_type_signatures; pub mod use_unique_element_ids; pub mod use_unique_graphql_operation_name; +pub mod use_unique_input_field_names; pub mod use_unique_variable_names; pub mod use_valid_anchor; pub mod use_valid_aria_props; diff --git a/crates/biome_rule_options/src/use_unique_input_field_names.rs b/crates/biome_rule_options/src/use_unique_input_field_names.rs new file mode 100644 index 000000000000..b4d266400e93 --- /dev/null +++ b/crates/biome_rule_options/src/use_unique_input_field_names.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 UseUniqueInputFieldNamesOptions {} diff --git a/packages/@biomejs/backend-jsonrpc/src/workspace.ts b/packages/@biomejs/backend-jsonrpc/src/workspace.ts index 7e8b8d29eecc..c1009cfaccbe 100644 --- a/packages/@biomejs/backend-jsonrpc/src/workspace.ts +++ b/packages/@biomejs/backend-jsonrpc/src/workspace.ts @@ -2137,6 +2137,11 @@ See */ useUniqueGraphqlOperationName?: UseUniqueGraphqlOperationNameConfiguration; /** + * Require fields within an input object to be unique. +See + */ + useUniqueInputFieldNames?: UseUniqueInputFieldNamesConfiguration; + /** * Require all variable definitions to be unique. See */ @@ -3785,6 +3790,9 @@ export type UseSpreadConfiguration = export type UseUniqueGraphqlOperationNameConfiguration = | RulePlainConfiguration | RuleWithUseUniqueGraphqlOperationNameOptions; +export type UseUniqueInputFieldNamesConfiguration = + | RulePlainConfiguration + | RuleWithUseUniqueInputFieldNamesOptions; export type UseUniqueVariableNamesConfiguration = | RulePlainConfiguration | RuleWithUseUniqueVariableNamesOptions; @@ -5280,6 +5288,10 @@ export interface RuleWithUseUniqueGraphqlOperationNameOptions { level: RulePlainConfiguration; options?: UseUniqueGraphqlOperationNameOptions; } +export interface RuleWithUseUniqueInputFieldNamesOptions { + level: RulePlainConfiguration; + options?: UseUniqueInputFieldNamesOptions; +} export interface RuleWithUseUniqueVariableNamesOptions { level: RulePlainConfiguration; options?: UseUniqueVariableNamesOptions; @@ -6570,6 +6582,7 @@ export interface UseSortedClassesOptions { } export type UseSpreadOptions = {}; export type UseUniqueGraphqlOperationNameOptions = {}; +export type UseUniqueInputFieldNamesOptions = {}; export type UseUniqueVariableNamesOptions = {}; export interface UseVueConsistentDefinePropsDeclarationOptions { style?: DeclarationStyle; @@ -7388,6 +7401,7 @@ export type Category = | "lint/nursery/useSortedClasses" | "lint/nursery/useSpread" | "lint/nursery/useUniqueGraphqlOperationName" + | "lint/nursery/useUniqueInputFieldNames" | "lint/nursery/useUniqueVariableNames" | "lint/nursery/useVueConsistentDefinePropsDeclaration" | "lint/nursery/useVueDefineMacrosOrder" diff --git a/packages/@biomejs/biome/configuration_schema.json b/packages/@biomejs/biome/configuration_schema.json index e1d5b0f87fea..625415c964d1 100644 --- a/packages/@biomejs/biome/configuration_schema.json +++ b/packages/@biomejs/biome/configuration_schema.json @@ -5561,6 +5561,13 @@ { "type": "null" } ] }, + "useUniqueInputFieldNames": { + "description": "Require fields within an input object to be unique.\nSee ", + "anyOf": [ + { "$ref": "#/$defs/UseUniqueInputFieldNamesConfiguration" }, + { "type": "null" } + ] + }, "useUniqueVariableNames": { "description": "Require all variable definitions to be unique.\nSee ", "anyOf": [ @@ -9739,6 +9746,15 @@ "additionalProperties": false, "required": ["level"] }, + "RuleWithUseUniqueInputFieldNamesOptions": { + "type": "object", + "properties": { + "level": { "$ref": "#/$defs/RulePlainConfiguration" }, + "options": { "$ref": "#/$defs/UseUniqueInputFieldNamesOptions" } + }, + "additionalProperties": false, + "required": ["level"] + }, "RuleWithUseUniqueVariableNamesOptions": { "type": "object", "properties": { @@ -12773,6 +12789,16 @@ "type": "object", "additionalProperties": false }, + "UseUniqueInputFieldNamesConfiguration": { + "oneOf": [ + { "$ref": "#/$defs/RulePlainConfiguration" }, + { "$ref": "#/$defs/RuleWithUseUniqueInputFieldNamesOptions" } + ] + }, + "UseUniqueInputFieldNamesOptions": { + "type": "object", + "additionalProperties": false + }, "UseUniqueVariableNamesConfiguration": { "oneOf": [ { "$ref": "#/$defs/RulePlainConfiguration" },