@@ -4,7 +4,7 @@ pub mod linter;
44use crate :: analyzer:: assist:: Actions ;
55pub use crate :: analyzer:: linter:: * ;
66use biome_analyze:: options:: RuleOptions ;
7- use biome_analyze:: { FixKind , RuleFilter } ;
7+ use biome_analyze:: { FixKind , RuleCategory , RuleFilter } ;
88use biome_deserialize:: {
99 Deserializable , DeserializableType , DeserializableValue , DeserializationContext , Merge ,
1010} ;
@@ -493,35 +493,94 @@ impl<'a> From<&'a RuleSelector> for RuleFilter<'static> {
493493impl FromStr for RuleSelector {
494494 type Err = & ' static str ;
495495 fn from_str ( selector : & str ) -> Result < Self , Self :: Err > {
496- let selector = selector
497- . strip_prefix ( "lint/" )
498- . or_else ( || selector. strip_prefix ( "assist/" ) )
499- . unwrap_or ( selector) ;
500-
501- if let Some ( ( group_name, rule_name) ) = selector. split_once ( '/' ) {
502- if let Ok ( group) = linter:: RuleGroup :: from_str ( group_name) {
503- if let Some ( rule_name) = Rules :: has_rule ( group, rule_name) {
504- Ok ( Self :: Rule ( group. as_str ( ) , rule_name) )
496+ let ( selector_kind, selector) = if let Some ( lint_selector) = selector. strip_prefix ( "lint/" )
497+ {
498+ ( Some ( RuleCategory :: Lint ) , lint_selector)
499+ } else if let Some ( assist_selector) = selector. strip_prefix ( "assist/" ) {
500+ ( Some ( RuleCategory :: Action ) , assist_selector)
501+ } else {
502+ ( None , selector)
503+ } ;
504+
505+ // If `optional_group_name` is set, then `rule_or_group_name` is a group.
506+ // Otherwise it is either a rule or a group.
507+ let ( optional_group_name, rule_or_group_name) =
508+ if let Some ( ( group_name, rule_name) ) = selector. split_once ( '/' ) {
509+ ( Some ( group_name) , rule_name)
510+ } else {
511+ ( None , selector)
512+ } ;
513+
514+ if let Ok ( rule_name) = linter:: RuleName :: from_str ( rule_or_group_name) {
515+ let static_group_name = rule_name. group ( ) . as_str ( ) ;
516+ // TODO: remove the `style/useNamingConvention` exception,
517+ // once we have promoted the GraphQL `useNamingConvention` rule.
518+ //
519+ // See https://github.com/biomejs/biome/issues/6018
520+ if optional_group_name. is_none_or ( |name| name == static_group_name)
521+ || ( rule_or_group_name == "useNamingConvention"
522+ && optional_group_name == Some ( "style" ) )
523+ {
524+ if matches ! ( selector_kind, None | Some ( RuleCategory :: Lint ) ) {
525+ // TODO: remove the `style/useNamingConvention` exception,
526+ // once we have promoted the GraphQL `useNamingConvention` rule.
527+ let static_group_name = if rule_or_group_name == "useNamingConvention"
528+ && optional_group_name == Some ( "style" )
529+ {
530+ "style"
531+ } else {
532+ static_group_name
533+ } ;
534+ Ok ( Self :: Rule ( static_group_name, rule_name. as_str ( ) ) )
505535 } else {
506- Err ( "This rule doesn't exist." )
536+ Err (
537+ "This is a lint rule and not an assist rule. Use the `lint/` prefix or remove the prefix." ,
538+ )
507539 }
508- } else if let Ok ( group) = assist:: RuleGroup :: from_str ( group_name) {
509- if let Some ( rule_name) = Actions :: has_rule ( group, rule_name) {
510- Ok ( Self :: Rule ( group. as_str ( ) , rule_name) )
540+ } else {
541+ Err ( "This rule is under a different group." )
542+ }
543+ } else if let Ok ( rule_name) = assist:: ActionName :: from_str ( rule_or_group_name) {
544+ let static_group_name = rule_name. group ( ) . as_str ( ) ;
545+ if optional_group_name. is_none_or ( |name| name == static_group_name) {
546+ if matches ! ( selector_kind, None | Some ( RuleCategory :: Action ) ) {
547+ Ok ( Self :: Rule ( static_group_name, rule_name. as_str ( ) ) )
511548 } else {
512- Err ( "This rule doesn't exist." )
549+ Err (
550+ "This is an assist rule and not a lint rule. Use the `assist/` prefix or remove the prefix." ,
551+ )
513552 }
514553 } else {
515- Err ( "This rule doesn't exist ." )
554+ Err ( "This action is under a different group ." )
516555 }
517- } else {
518- if let Ok ( group) = linter:: RuleGroup :: from_str ( selector) {
519- return Ok ( Self :: Group ( group. as_str ( ) ) ) ;
556+ } else if let Some ( group_name) = optional_group_name {
557+ Err ( if linter:: RuleGroup :: from_str ( group_name) . is_ok ( ) {
558+ "This rule doesn't exist."
559+ } else if assist:: RuleGroup :: from_str ( group_name) . is_ok ( ) {
560+ "This action doesn't exist."
561+ } else {
562+ "This rule or action doesn't exist."
563+ } )
564+ } else if let Ok ( group) = linter:: RuleGroup :: from_str ( rule_or_group_name) {
565+ if matches ! ( selector_kind, None | Some ( RuleCategory :: Lint ) ) {
566+ Ok ( Self :: Group ( group. as_str ( ) ) )
567+ } else {
568+ Err (
569+ "This is a lint group and not an assist group. Use the `lint/` prefix or remove the prefix." ,
570+ )
520571 }
521- if let Ok ( group) = assist:: RuleGroup :: from_str ( selector) {
522- return Ok ( Self :: Group ( group. as_str ( ) ) ) ;
572+ } else if let Ok ( group) = assist:: RuleGroup :: from_str ( rule_or_group_name) {
573+ if matches ! ( selector_kind, None | Some ( RuleCategory :: Action ) ) {
574+ Ok ( Self :: Group ( group. as_str ( ) ) )
575+ } else {
576+ Err (
577+ "This is an assist group and not a lint group. Use the `assist/` prefix or remove the prefix." ,
578+ )
523579 }
524- Err ( "This group doesn't exist. Use the syntax `<group>/<rule>` to specify a rule." )
580+ } else if rule_or_group_name. bytes ( ) . all ( |c| c. is_ascii_lowercase ( ) ) {
581+ Err ( "This group doesn't exist." )
582+ } else {
583+ Err ( "This rule name or action name doesn't exist." )
525584 }
526585 }
527586}
0 commit comments