@@ -13,7 +13,7 @@ function pluralize(word: string, count: number): string {
1313// Simple function to strip ANSI codes for length calculation
1414function stripAnsi ( str : string ) : string {
1515 // eslint-disable-next-line no-control-regex
16- return str . replace ( / \u001b \[ [ 0 - 9 ; ] * m / g, '' ) ;
16+ return str . replace ( / \u001B \[ [ \d ; ] * m / g, '' ) ;
1717}
1818
1919// Simple table formatting function
@@ -23,22 +23,31 @@ function createTable(
2323) : string {
2424 const { align = [ ] , stringLength = s => s . length } = options ;
2525
26- if ( data . length === 0 ) return '' ;
26+ if ( data . length === 0 ) {
27+ return '' ;
28+ }
2729
2830 // Calculate column widths
29- const colWidths : number [ ] = [ ] ;
30- data . forEach ( row => {
31- row . forEach ( ( cell , colIndex ) => {
32- const cellStr = String ( cell ) ;
33- const width = stringLength ( cellStr ) ;
34- colWidths [ colIndex ] = Math . max ( colWidths [ colIndex ] || 0 , width ) ;
35- } ) ;
36- } ) ;
31+ const colWidths : number [ ] = data . reduce < number [ ] > (
32+ ( widths , row ) =>
33+ row . reduce < number [ ] > ( ( acc , cell , colIndex ) => {
34+ const cellStr = String ( cell ) ;
35+ const width = stringLength ( cellStr ) ;
36+ const currentWidth = acc [ colIndex ] || 0 ;
37+ const maxWidth = Math . max ( currentWidth , width ) ;
38+ return [
39+ ...acc . slice ( 0 , colIndex ) ,
40+ maxWidth ,
41+ ...acc . slice ( colIndex + 1 ) ,
42+ ] ;
43+ } , widths ) ,
44+ [ ] ,
45+ ) ;
3746
3847 // Format rows
3948 return data
40- . map ( row => {
41- return row
49+ . map ( row =>
50+ row
4251 . map ( ( cell , colIndex ) => {
4352 const cellStr = String ( cell ) ;
4453 const width = colWidths [ colIndex ] || 0 ;
@@ -49,148 +58,139 @@ function createTable(
4958 }
5059 return cellStr + ' ' . repeat ( padding ) ;
5160 } )
52- . join ( ' ' ) ;
53- } )
61+ . join ( ' ' ) ,
62+ )
5463 . join ( '\n' ) ;
5564}
5665
57- // Inline stylish formatter implementation using ansis
58- function stylishFormatter ( results : ESLint . LintResult [ ] ) : string {
59- let output = '\n' ;
60- let errorCount = 0 ;
61- let warningCount = 0 ;
62- let fixableErrorCount = 0 ;
63- let fixableWarningCount = 0 ;
64- let summaryColor = 'yellow' as 'yellow' | 'red' ;
65-
66- results . forEach ( result => {
67- const messages = result . messages ;
68-
69- if ( messages . length === 0 ) {
70- return ;
71- }
66+ // Summary statistics for lint results
67+ type LintSummary = {
68+ errorCount : number ;
69+ warningCount : number ;
70+ fixableErrorCount : number ;
71+ fixableWarningCount : number ;
72+ summaryColor : 'yellow' | 'red' ;
73+ } ;
7274
73- errorCount += result . errorCount ;
74- warningCount += result . warningCount ;
75- fixableErrorCount += result . fixableErrorCount ;
76- fixableWarningCount += result . fixableWarningCount ;
77-
78- output += `${ underline ( result . filePath ) } \n` ;
79-
80- const tableData = messages . map ( message => {
81- let messageType : string ;
82-
83- if ( message . fatal || message . severity === 2 ) {
84- messageType = red ( 'error' ) ;
85- summaryColor = 'red' ;
86- } else {
87- messageType = yellow ( 'warning' ) ;
88- }
89-
90- return [
91- '' ,
92- message . line || 0 ,
93- message . column || 0 ,
94- messageType ,
95- message . message . replace ( / ( [ ^ ] ) \. $ / u, '$1' ) ,
96- dim ( message . ruleId || '' ) ,
97- ] ;
98- } ) ;
99-
100- const table = createTable ( tableData , {
101- align : [ '' , 'r' , 'l' ] ,
102- stringLength : ( str : string ) => stripAnsi ( str ) . length ,
103- } ) ;
104-
105- // Format line:column numbers with dim styling
106- const formattedTable = table
107- . split ( '\n' )
108- . map ( line =>
109- line . replace ( / ( \d + ) \s + ( \d + ) / u, ( m , p1 , p2 ) => dim ( `${ p1 } :${ p2 } ` ) ) ,
110- )
111- . join ( '\n' ) ;
112-
113- output += `${ formattedTable } \n\n` ;
75+ // Calculate summary statistics from results
76+ function calculateSummary ( results : ESLint . LintResult [ ] ) : LintSummary {
77+ return results . reduce < LintSummary > (
78+ ( summary , result ) => ( {
79+ errorCount : summary . errorCount + result . errorCount ,
80+ warningCount : summary . warningCount + result . warningCount ,
81+ fixableErrorCount : summary . fixableErrorCount + result . fixableErrorCount ,
82+ fixableWarningCount :
83+ summary . fixableWarningCount + result . fixableWarningCount ,
84+ summaryColor :
85+ result . errorCount > 0 ? ( 'red' as const ) : summary . summaryColor ,
86+ } ) ,
87+ {
88+ errorCount : 0 ,
89+ warningCount : 0 ,
90+ fixableErrorCount : 0 ,
91+ fixableWarningCount : 0 ,
92+ summaryColor : 'yellow' ,
93+ } ,
94+ ) ;
95+ }
96+
97+ // Format a single result file
98+ function formatResultFile ( result : ESLint . LintResult ) : string {
99+ if ( result . messages . length === 0 ) {
100+ return '' ;
101+ }
102+
103+ const header = `${ underline ( result . filePath ) } \n` ;
104+
105+ const tableData = result . messages . map ( message => {
106+ const messageType =
107+ message . fatal || message . severity === 2
108+ ? red ( 'error' )
109+ : yellow ( 'warning' ) ;
110+
111+ return [
112+ '' ,
113+ message . line || 0 ,
114+ message . column || 0 ,
115+ messageType ,
116+ message . message . replace ( / ( [ ^ ] ) \. $ / u, '$1' ) ,
117+ dim ( message . ruleId || '' ) ,
118+ ] ;
114119 } ) ;
115120
116- const total = errorCount + warningCount ;
121+ const table = createTable ( tableData , {
122+ align : [ '' , 'r' , 'l' ] ,
123+ stringLength : ( str : string ) => stripAnsi ( str ) . length ,
124+ } ) ;
117125
118- if ( total > 0 ) {
119- if ( summaryColor === 'red' ) {
120- output += bold (
121- red (
122- [
123- '\u2716 ' ,
124- total ,
125- pluralize ( ' problem' , total ) ,
126- ' (' ,
127- errorCount ,
128- pluralize ( ' error' , errorCount ) ,
129- ', ' ,
130- warningCount ,
131- pluralize ( ' warning' , warningCount ) ,
132- ')\n' ,
133- ] . join ( '' ) ,
134- ) ,
135- ) ;
126+ const formattedTable = table
127+ . split ( '\n' )
128+ . map ( line =>
129+ line . replace ( / ( \d + ) \s + ( \d + ) / u, ( m , p1 , p2 ) => dim ( `${ p1 } :${ p2 } ` ) ) ,
130+ )
131+ . join ( '\n' ) ;
136132
137- if ( fixableErrorCount > 0 || fixableWarningCount > 0 ) {
138- output += bold (
139- red (
140- [
141- ' ' ,
142- fixableErrorCount ,
143- pluralize ( ' error' , fixableErrorCount ) ,
144- ' and ' ,
145- fixableWarningCount ,
146- pluralize ( ' warning' , fixableWarningCount ) ,
147- ' potentially fixable with the `--fix` option.\n' ,
148- ] . join ( '' ) ,
149- ) ,
150- ) ;
151- }
152- } else {
153- output += bold (
154- yellow (
155- [
156- '\u2716 ' ,
157- total ,
158- pluralize ( ' problem' , total ) ,
159- ' (' ,
160- errorCount ,
161- pluralize ( ' error' , errorCount ) ,
162- ', ' ,
163- warningCount ,
164- pluralize ( ' warning' , warningCount ) ,
165- ')\n' ,
166- ] . join ( '' ) ,
167- ) ,
168- ) ;
133+ return `${ header } ${ formattedTable } \n\n` ;
134+ }
169135
170- if ( fixableErrorCount > 0 || fixableWarningCount > 0 ) {
171- output += bold (
172- yellow (
173- [
174- ' ' ,
175- fixableErrorCount ,
176- pluralize ( ' error' , fixableErrorCount ) ,
177- ' and ' ,
178- fixableWarningCount ,
179- pluralize ( ' warning' , fixableWarningCount ) ,
180- ' potentially fixable with the `--fix` option.\n' ,
181- ] . join ( '' ) ,
182- ) ,
183- ) ;
184- }
185- }
136+ // Format summary section
137+ function formatSummary ( summary : LintSummary ) : string {
138+ const {
139+ errorCount,
140+ warningCount,
141+ fixableErrorCount,
142+ fixableWarningCount,
143+ summaryColor,
144+ } = summary ;
145+ const total = errorCount + warningCount ;
146+
147+ if ( total === 0 ) {
148+ return '' ;
149+ }
150+
151+ const colorFn = summaryColor === 'red' ? red : yellow ;
152+ const problemText = [
153+ '\u2716 ' ,
154+ total ,
155+ pluralize ( ' problem' , total ) ,
156+ ' (' ,
157+ errorCount ,
158+ pluralize ( ' error' , errorCount ) ,
159+ ', ' ,
160+ warningCount ,
161+ pluralize ( ' warning' , warningCount ) ,
162+ ')\n' ,
163+ ] . join ( '' ) ;
164+
165+ const problemOutput = bold ( colorFn ( problemText ) ) ;
166+
167+ if ( fixableErrorCount > 0 || fixableWarningCount > 0 ) {
168+ const fixableText = [
169+ ' ' ,
170+ fixableErrorCount ,
171+ pluralize ( ' error' , fixableErrorCount ) ,
172+ ' and ' ,
173+ fixableWarningCount ,
174+ pluralize ( ' warning' , fixableWarningCount ) ,
175+ ' potentially fixable with the `--fix` option.\n' ,
176+ ] . join ( '' ) ;
177+
178+ return problemOutput + bold ( colorFn ( fixableText ) ) ;
186179 }
187180
188- // Reset output color to prevent changes at top level
189- return total > 0 ? reset ( output ) : '' ;
181+ return problemOutput ;
182+ }
183+
184+ function stylishFormatter ( results : ESLint . LintResult [ ] ) : string {
185+ const summary = calculateSummary ( results ) ;
186+ const filesOutput = results . map ( formatResultFile ) . join ( '' ) ;
187+ const summaryOutput = formatSummary ( summary ) ;
188+
189+ const total = summary . errorCount + summary . warningCount ;
190+ return total > 0 ? reset ( `\n${ filesOutput } ${ summaryOutput } ` ) : '' ;
190191}
191192
192193export function stringifyError ( error : unknown ) : string {
193- // TODO: special handling for ZodError instances
194194 if ( error instanceof Error ) {
195195 if ( error . name === 'Error' || error . message . startsWith ( error . name ) ) {
196196 return error . message ;
0 commit comments