@@ -2,12 +2,33 @@ use pgls_analyse::RuleFilter;
22
33use std:: str:: FromStr ;
44
5- use crate :: { Rules , linter:: RuleGroup } ;
5+ /// Represents a rule group from any analyzer (linter or splinter)
6+ #[ derive( Clone , Copy , Debug , Eq , PartialEq , Hash ) ]
7+ pub enum AnalyzerGroup {
8+ Linter ( crate :: linter:: RuleGroup ) ,
9+ Splinter ( crate :: splinter:: RuleGroup ) ,
10+ }
11+
12+ impl AnalyzerGroup {
13+ pub const fn as_str ( self ) -> & ' static str {
14+ match self {
15+ Self :: Linter ( group) => group. as_str ( ) ,
16+ Self :: Splinter ( group) => group. as_str ( ) ,
17+ }
18+ }
19+
20+ pub const fn category_prefix ( & self ) -> & ' static str {
21+ match self {
22+ Self :: Linter ( _) => "lint" ,
23+ Self :: Splinter ( _) => "splinter" ,
24+ }
25+ }
26+ }
627
728#[ derive( Clone , Copy , Debug , Eq , PartialEq , Hash ) ]
829pub enum RuleSelector {
9- Group ( RuleGroup ) ,
10- Rule ( RuleGroup , & ' static str ) ,
30+ Group ( AnalyzerGroup ) ,
31+ Rule ( AnalyzerGroup , & ' static str ) ,
1132}
1233
1334impl From < RuleSelector > for RuleFilter < ' static > {
@@ -31,20 +52,56 @@ impl<'a> From<&'a RuleSelector> for RuleFilter<'static> {
3152impl FromStr for RuleSelector {
3253 type Err = & ' static str ;
3354 fn from_str ( selector : & str ) -> Result < Self , Self :: Err > {
34- let selector = selector. strip_prefix ( "lint/" ) . unwrap_or ( selector) ;
35- if let Some ( ( group_name, rule_name) ) = selector. split_once ( '/' ) {
36- let group = RuleGroup :: from_str ( group_name) ?;
37- if let Some ( rule_name) = Rules :: has_rule ( group, rule_name) {
38- Ok ( RuleSelector :: Rule ( group, rule_name) )
39- } else {
40- Err ( "This rule doesn't exist." )
55+ // Try to detect the analyzer from the prefix
56+ let ( analyzer_type, rest) = if let Some ( rest) = selector. strip_prefix ( "lint/" ) {
57+ ( "lint" , rest)
58+ } else if let Some ( rest) = selector. strip_prefix ( "splinter/" ) {
59+ ( "splinter" , rest)
60+ } else {
61+ // Default to lint for backward compatibility
62+ ( "lint" , selector)
63+ } ;
64+
65+ if let Some ( ( group_name, rule_name) ) = rest. split_once ( '/' ) {
66+ // Parse as <group>/<rule>
67+ match analyzer_type {
68+ "lint" => {
69+ let group = crate :: linter:: RuleGroup :: from_str ( group_name) ?;
70+ if let Some ( rule_name) = crate :: linter:: Rules :: has_rule ( group, rule_name) {
71+ Ok ( RuleSelector :: Rule ( AnalyzerGroup :: Linter ( group) , rule_name) )
72+ } else {
73+ Err ( "This rule doesn't exist." )
74+ }
75+ }
76+ "splinter" => {
77+ let group = crate :: splinter:: RuleGroup :: from_str ( group_name) ?;
78+ if let Some ( rule_name) = crate :: splinter:: Rules :: has_rule ( group, rule_name) {
79+ Ok ( RuleSelector :: Rule (
80+ AnalyzerGroup :: Splinter ( group) ,
81+ rule_name,
82+ ) )
83+ } else {
84+ Err ( "This rule doesn't exist." )
85+ }
86+ }
87+ _ => Err ( "Unknown analyzer type." ) ,
4188 }
4289 } else {
43- match RuleGroup :: from_str ( selector) {
44- Ok ( group) => Ok ( RuleSelector :: Group ( group) ) ,
45- Err ( _) => Err (
46- "This group doesn't exist. Use the syntax `<group>/<rule>` to specify a rule." ,
47- ) ,
90+ // Parse as just <group>
91+ match analyzer_type {
92+ "lint" => match crate :: linter:: RuleGroup :: from_str ( rest) {
93+ Ok ( group) => Ok ( RuleSelector :: Group ( AnalyzerGroup :: Linter ( group) ) ) ,
94+ Err ( _) => Err (
95+ "This group doesn't exist. Use the syntax `<group>/<rule>` to specify a rule." ,
96+ ) ,
97+ } ,
98+ "splinter" => match crate :: splinter:: RuleGroup :: from_str ( rest) {
99+ Ok ( group) => Ok ( RuleSelector :: Group ( AnalyzerGroup :: Splinter ( group) ) ) ,
100+ Err ( _) => Err (
101+ "This group doesn't exist. Use the syntax `<group>/<rule>` to specify a rule." ,
102+ ) ,
103+ } ,
104+ _ => Err ( "Unknown analyzer type." ) ,
48105 }
49106 }
50107 }
@@ -53,10 +110,15 @@ impl FromStr for RuleSelector {
53110impl serde:: Serialize for RuleSelector {
54111 fn serialize < S : serde:: Serializer > ( & self , serializer : S ) -> Result < S :: Ok , S :: Error > {
55112 match self {
56- RuleSelector :: Group ( group) => serializer. serialize_str ( group. as_str ( ) ) ,
113+ RuleSelector :: Group ( group) => {
114+ let prefix = group. category_prefix ( ) ;
115+ let group_name = group. as_str ( ) ;
116+ serializer. serialize_str ( & format ! ( "{prefix}/{group_name}" ) )
117+ }
57118 RuleSelector :: Rule ( group, rule_name) => {
119+ let prefix = group. category_prefix ( ) ;
58120 let group_name = group. as_str ( ) ;
59- serializer. serialize_str ( & format ! ( "{group_name}/{rule_name}" ) )
121+ serializer. serialize_str ( & format ! ( "{prefix}/{ group_name}/{rule_name}" ) )
60122 }
61123 }
62124 }
@@ -68,7 +130,7 @@ impl<'de> serde::Deserialize<'de> for RuleSelector {
68130 impl serde:: de:: Visitor < ' _ > for Visitor {
69131 type Value = RuleSelector ;
70132 fn expecting ( & self , formatter : & mut std:: fmt:: Formatter ) -> std:: fmt:: Result {
71- formatter. write_str ( "<group>/<ruyle_name >" )
133+ formatter. write_str ( "<group>/<rule_name >" )
72134 }
73135 fn visit_str < E : serde:: de:: Error > ( self , v : & str ) -> Result < Self :: Value , E > {
74136 match RuleSelector :: from_str ( v) {
0 commit comments