@@ -15,6 +15,10 @@ pub struct Scope {
1515 /// Options represents the options of the rule.
1616 /// If the option is empty, it means that no scope is allowed.
1717 options : Vec < String > ,
18+
19+ /// Optional scope.
20+ /// If true, even if the scope is not present, it is allowed.
21+ optional : bool ,
1822}
1923
2024/// Scope represents the scope rule.
@@ -37,7 +41,7 @@ impl Rule for Scope {
3741 fn validate ( & self , message : & Message ) -> Option < Violation > {
3842 match & message. scope {
3943 None => {
40- if self . options . is_empty ( ) {
44+ if self . options . is_empty ( ) || self . optional {
4145 return None ;
4246 }
4347 }
@@ -64,6 +68,7 @@ impl Default for Scope {
6468 fn default ( ) -> Self {
6569 Self {
6670 level : Some ( Self :: LEVEL ) ,
71+ optional : false ,
6772 options : vec ! [ ] ,
6873 }
6974 }
@@ -235,5 +240,54 @@ mod tests {
235240 "scope invalid is not allowed. Only [\" api\" , \" web\" ] are allowed" . to_string( )
236241 ) ;
237242 }
243+
244+ #[ test]
245+ fn test_optional_scope_with_non_empty_scope ( ) {
246+ let rule = Scope {
247+ options : vec ! [ "api" . to_string( ) , "web" . to_string( ) ] ,
248+ optional : true ,
249+ ..Default :: default ( )
250+ } ;
251+
252+ let message = Message {
253+ body : None ,
254+ description : None ,
255+ footers : None ,
256+ r#type : Some ( "feat" . to_string ( ) ) ,
257+ raw : "feat(invalid): broadcast $destroy event on scope destruction" . to_string ( ) ,
258+ scope : Some ( "invalid" . to_string ( ) ) ,
259+ subject : None ,
260+ } ;
261+
262+ let violation = rule. validate ( & message) ;
263+ assert ! ( violation. is_some( ) ) ;
264+ assert_eq ! ( violation. clone( ) . unwrap( ) . level, Level :: Error ) ;
265+ assert_eq ! (
266+ violation. unwrap( ) . message,
267+ "scope invalid is not allowed. Only [\" api\" , \" web\" ] are allowed" . to_string( )
268+ ) ;
269+ }
270+
271+ #[ test]
272+ fn test_optional_scope_with_empty_scope ( ) {
273+ let rule = Scope {
274+ options : vec ! [ "api" . to_string( ) , "web" . to_string( ) ] ,
275+ optional : true ,
276+ ..Default :: default ( )
277+ } ;
278+
279+ let message = Message {
280+ body : None ,
281+ description : None ,
282+ footers : None ,
283+ r#type : Some ( "feat" . to_string ( ) ) ,
284+ raw : "feat: broadcast $destroy event on scope destruction" . to_string ( ) ,
285+ scope : None ,
286+ subject : None ,
287+ } ;
288+
289+ let violation = rule. validate ( & message) ;
290+ assert ! ( violation. is_none( ) ) ;
291+ }
238292 }
239293}
0 commit comments