@@ -156,44 +156,18 @@ impl LinterBuilder {
156156
157157 pub fn with_filter ( mut self , filter : LintFilter ) -> Self {
158158 let ( severity, filter) = filter. into ( ) ;
159- let all_rules = self . cache . borrow ( ) ;
160159
161160 match severity {
162161 AllowWarnDeny :: Deny | AllowWarnDeny :: Warn => match filter {
163162 LintFilterKind :: Category ( category) => {
164- let rules_to_configure = all_rules. iter ( ) . filter ( |r| r. category ( ) == category) ;
165- for rule in rules_to_configure {
166- if let Some ( mut existing_rule) = self . rules . take ( rule) {
167- existing_rule. severity = severity;
168- self . rules . insert ( existing_rule) ;
169- } else {
170- self . rules . insert ( RuleWithSeverity :: new ( rule. clone ( ) , severity) ) ;
171- }
172- }
173- }
174- LintFilterKind :: Rule ( _, name) => {
175- self . rules . extend (
176- all_rules
177- . iter ( )
178- . filter ( |rule| rule. name ( ) == name)
179- . map ( |rule| RuleWithSeverity :: new ( rule. clone ( ) , severity) ) ,
180- ) ;
163+ self . upsert_where ( severity, |r| r. category ( ) == category) ;
181164 }
165+ LintFilterKind :: Rule ( _, name) => self . upsert_where ( severity, |r| r. name ( ) == name) ,
182166 LintFilterKind :: Generic ( name_or_category) => {
183167 if name_or_category == "all" {
184- self . rules . extend (
185- all_rules
186- . iter ( )
187- . filter ( |rule| rule. category ( ) != RuleCategory :: Nursery )
188- . map ( |rule| RuleWithSeverity :: new ( rule. clone ( ) , severity) ) ,
189- ) ;
168+ self . upsert_where ( severity, |r| r. category ( ) != RuleCategory :: Nursery ) ;
190169 } else {
191- self . rules . extend (
192- all_rules
193- . iter ( )
194- . filter ( |rule| rule. name ( ) == name_or_category)
195- . map ( |rule| RuleWithSeverity :: new ( rule. clone ( ) , severity) ) ,
196- ) ;
170+ self . upsert_where ( severity, |r| r. name ( ) == name_or_category) ;
197171 }
198172 }
199173 } ,
@@ -213,11 +187,30 @@ impl LinterBuilder {
213187 }
214188 } ,
215189 }
216- drop ( all_rules) ;
217190
218191 self
219192 }
220193
194+ /// Warn/Deny a let of rules based on some predicate. Rules already in `self.rules` get
195+ /// re-configured, while those that are not are added. Affects rules where `query` returns
196+ /// `true`.
197+ fn upsert_where < F > ( & mut self , severity : AllowWarnDeny , query : F )
198+ where
199+ F : Fn ( & & RuleEnum ) -> bool ,
200+ {
201+ let all_rules = self . cache . borrow ( ) ;
202+ // NOTE: we may want to warn users if they're configuring a rule that does not exist.
203+ let rules_to_configure = all_rules. iter ( ) . filter ( query) ;
204+ for rule in rules_to_configure {
205+ if let Some ( mut existing_rule) = self . rules . take ( rule) {
206+ existing_rule. severity = severity;
207+ self . rules . insert ( existing_rule) ;
208+ } else {
209+ self . rules . insert ( RuleWithSeverity :: new ( rule. clone ( ) , severity) ) ;
210+ }
211+ }
212+ }
213+
221214 #[ must_use]
222215 pub fn build ( self ) -> Linter {
223216 // When a plugin gets disabled before build(), rules for that plugin aren't removed until
@@ -403,6 +396,47 @@ mod test {
403396 }
404397 }
405398
399+ // change a rule already set to "warn" to "deny"
400+ #[ test]
401+ fn test_filter_deny_single_enabled_rule_on_default ( ) {
402+ for filter_string in [ "no-const-assign" , "eslint/no-const-assign" ] {
403+ let builder = LinterBuilder :: default ( ) ;
404+ let initial_rule_count = builder. rules . len ( ) ;
405+
406+ let builder =
407+ builder
408+ . with_filters ( [ LintFilter :: new ( AllowWarnDeny :: Deny , filter_string) . unwrap ( ) ] ) ;
409+ let rule_count_after_deny = builder. rules . len ( ) ;
410+ assert_eq ! ( initial_rule_count, rule_count_after_deny, "Changing a single rule from warn to deny should not add a new one, just modify what's already there." ) ;
411+
412+ let no_const_assign = builder
413+ . rules
414+ . iter ( )
415+ . find ( |r| r. plugin_name ( ) == "eslint" && r. name ( ) == "no-const-assign" )
416+ . expect ( "Could not find eslint/no-const-assign after configuring it to 'deny'" ) ;
417+ assert_eq ! ( no_const_assign. severity, AllowWarnDeny :: Deny ) ;
418+ }
419+ }
420+ // turn on a rule that isn't configured yet and set it to "warn"
421+ // note that this is an eslint rule, a plugin that's already turned on.
422+ #[ test]
423+ fn test_filter_warn_single_disabled_rule_on_default ( ) {
424+ for filter_string in [ "no-console" , "eslint/no-console" ] {
425+ let filter = LintFilter :: new ( AllowWarnDeny :: Warn , filter_string) . unwrap ( ) ;
426+ let builder = LinterBuilder :: default ( ) ;
427+ // sanity check: not already turned on
428+ assert ! ( !builder. rules. iter( ) . any( |r| r. name( ) == "no-console" ) ) ;
429+ let builder = builder. with_filter ( filter) ;
430+ let no_console = builder
431+ . rules
432+ . iter ( )
433+ . find ( |r| r. plugin_name ( ) == "eslint" && r. name ( ) == "no-console" )
434+ . expect ( "Could not find eslint/no-console after configuring it to 'warn'" ) ;
435+
436+ assert_eq ! ( no_console. severity, AllowWarnDeny :: Warn ) ;
437+ }
438+ }
439+
406440 #[ test]
407441 fn test_filter_allow_all_then_warn ( ) {
408442 let builder =
0 commit comments