@@ -147,7 +147,7 @@ export class CLI {
147147 const startTime = Date . now ( )
148148 const startDate = new Date ( )
149149
150- const { patterns, configFile, formatOption, showTiming, theme, wrapLines, truncateLines, useGitHubActions, fix, fixUnsafe, ignoreDisableComments, force, init, upgrade, loadCustomRules, failLevel, jobs } = this . argumentParser . parse ( process . argv )
150+ const { patterns, configFile, formatOption, showTiming, theme, wrapLines, truncateLines, useGitHubActions, fix, fixUnsafe, ignoreDisableComments, force, init, upgrade, disableFailing , loadCustomRules, failLevel, jobs } = this . argumentParser . parse ( process . argv )
151151
152152 this . determineProjectPath ( patterns )
153153
@@ -225,8 +225,11 @@ export class CLI {
225225 const upgradeProcessor = new FileProcessor ( )
226226 const results = await upgradeProcessor . processFiles ( files , 'json' , upgradeContext )
227227
228- for ( const [ ruleName , data ] of results . ruleOffenses ) {
229- ruleOffenseCounts . set ( ruleName , data . count )
228+ for ( const { offense } of results . allOffenses ) {
229+ if ( offense . severity !== "error" && offense . severity !== "warning" ) continue
230+
231+ const ruleName = offense . code || ""
232+ ruleOffenseCounts . set ( ruleName , ( ruleOffenseCounts . get ( ruleName ) || 0 ) + 1 )
230233 }
231234
232235 rulesToDisable = skippedByVersion . filter ( rule => ruleOffenseCounts . has ( rule . ruleName ) )
@@ -281,6 +284,68 @@ export class CLI {
281284 process . exit ( 0 )
282285 }
283286
287+ if ( disableFailing ) {
288+ const configPath = configFile || this . projectPath
289+
290+ if ( ! Config . exists ( configPath ) ) {
291+ console . error ( `\n✗ No .herb.yml found. Run ${ colorize ( "herb-lint --init" , "cyan" ) } first.\n` )
292+ process . exit ( 1 )
293+ }
294+
295+ const config = await Config . load ( configPath , { version, exitOnError : true , createIfMissing : false , silent : true } )
296+
297+ console . log ( `\n${ colorize ( "↻" , "cyan" ) } Linting codebase to find rules with offenses...` )
298+
299+ await Herb . load ( )
300+
301+ const files = await config . findFilesForTool ( 'linter' , this . projectPath )
302+
303+ const disableFailingContext : ProcessingContext = {
304+ projectPath : this . projectPath ,
305+ config,
306+ jobs,
307+ }
308+
309+ const processor = new FileProcessor ( )
310+ const results = await processor . processFiles ( files , 'json' , disableFailingContext )
311+ const failingRules = new Map < string , number > ( )
312+ const PROTECTED_RULES = new Set ( [ "parser-no-errors" ] )
313+
314+ for ( const { offense } of results . allOffenses ) {
315+ if ( PROTECTED_RULES . has ( offense . code || "" ) ) continue
316+ if ( offense . severity !== "error" && offense . severity !== "warning" ) continue
317+
318+ failingRules . set ( offense . code || "" , ( failingRules . get ( offense . code || "" ) || 0 ) + 1 )
319+ }
320+
321+ if ( failingRules . size === 0 ) {
322+ console . log ( `\n${ colorize ( "✓" , "brightGreen" ) } No offenses found. All rules are passing!\n` )
323+ process . exit ( 0 )
324+ }
325+
326+ const rulesMutation : Record < string , { enabled : boolean } > = { }
327+
328+ for ( const ruleName of failingRules . keys ( ) ) {
329+ rulesMutation [ ruleName ] = { enabled : false }
330+ }
331+
332+ await Config . mutateConfigFile ( config . path , {
333+ linter : { rules : rulesMutation }
334+ } )
335+
336+ const totalOffenses = Array . from ( failingRules . values ( ) ) . reduce ( ( sum , count ) => sum + count , 0 )
337+ const sortedRules = Array . from ( failingRules . entries ( ) ) . sort ( ( a , b ) => b [ 1 ] - a [ 1 ] )
338+
339+ console . log ( `\n${ colorize ( "!" , "yellow" ) } Found ${ colorize ( String ( totalOffenses ) , "bold" ) } ${ totalOffenses === 1 ? "offense" : "offenses" } across ${ colorize ( String ( failingRules . size ) , "bold" ) } ${ failingRules . size === 1 ? "rule" : "rules" } . Disabled in ${ colorize ( ".herb.yml" , "cyan" ) } :\n` )
340+
341+ for ( const [ ruleName , count ] of sortedRules ) {
342+ console . log ( ` ${ colorize ( "✗" , "red" ) } ${ colorize ( ruleName , "white" ) } ${ colorize ( `(${ count } ${ count === 1 ? "offense" : "offenses" } )` , "gray" ) } ` )
343+ }
344+
345+ console . log ( `\n When you're ready, review the disabled rules in your ${ colorize ( ".herb.yml" , "cyan" ) } and re-enable them after fixing the offenses.\n` )
346+ process . exit ( 0 )
347+ }
348+
284349 const silent = formatOption === 'json'
285350 const config = await Config . load ( configFile || this . projectPath , { version, exitOnError : true , createIfMissing : false , silent } )
286351 const linterConfig = config . options . linter || { }
0 commit comments