mirror of
https://github.com/mgechev/revive.git
synced 2025-07-01 00:24:54 +02:00
* Rewrite Friendly.table method to replace tablewriter with fmt.Fprintf * Refactor Stylish formatter to use custom table rendering instead of tablewriter * Refactor Friendly and Stylish formatters to utilize a new custom table rendering function * Remove unused dependencies from go.mod and go.sum * Refactor table formatting by replacing formatTable with a new table function in friendly.go * Utilize text/tabwriter in fromatting a table * Refactor table function to use bytes.Buffer for improved performance
144 lines
3.6 KiB
Go
144 lines
3.6 KiB
Go
package formatter
|
|
|
|
import (
|
|
"bytes"
|
|
"cmp"
|
|
"fmt"
|
|
"io"
|
|
"slices"
|
|
"strings"
|
|
"text/tabwriter"
|
|
|
|
"github.com/fatih/color"
|
|
"github.com/mgechev/revive/lint"
|
|
)
|
|
|
|
func getErrorEmoji() string {
|
|
return color.RedString("✘")
|
|
}
|
|
|
|
func getWarningEmoji() string {
|
|
return color.YellowString("⚠")
|
|
}
|
|
|
|
// Friendly is an implementation of the Formatter interface
|
|
// which formats the errors to JSON.
|
|
type Friendly struct {
|
|
Metadata lint.FormatterMetadata
|
|
}
|
|
|
|
// Name returns the name of the formatter
|
|
func (*Friendly) Name() string {
|
|
return "friendly"
|
|
}
|
|
|
|
// Format formats the failures gotten from the lint.
|
|
func (f *Friendly) Format(failures <-chan lint.Failure, config lint.Config) (string, error) {
|
|
var buf strings.Builder
|
|
errorMap := map[string]int{}
|
|
warningMap := map[string]int{}
|
|
totalErrors := 0
|
|
totalWarnings := 0
|
|
for failure := range failures {
|
|
sev := severity(config, failure)
|
|
f.printFriendlyFailure(&buf, failure, sev)
|
|
switch sev {
|
|
case lint.SeverityWarning:
|
|
warningMap[failure.RuleName]++
|
|
totalWarnings++
|
|
case lint.SeverityError:
|
|
errorMap[failure.RuleName]++
|
|
totalErrors++
|
|
}
|
|
}
|
|
|
|
f.printSummary(&buf, totalErrors, totalWarnings)
|
|
f.printStatistics(&buf, color.RedString("Errors:"), errorMap)
|
|
f.printStatistics(&buf, color.YellowString("Warnings:"), warningMap)
|
|
return buf.String(), nil
|
|
}
|
|
|
|
func (f *Friendly) printFriendlyFailure(sb *strings.Builder, failure lint.Failure, severity lint.Severity) {
|
|
f.printHeaderRow(sb, failure, severity)
|
|
f.printFilePosition(sb, failure)
|
|
sb.WriteString("\n\n")
|
|
}
|
|
|
|
func (*Friendly) printHeaderRow(sb *strings.Builder, failure lint.Failure, severity lint.Severity) {
|
|
emoji := getWarningEmoji()
|
|
if severity == lint.SeverityError {
|
|
emoji = getErrorEmoji()
|
|
}
|
|
sb.WriteString(table([][]string{{emoji, ruleDescriptionURL(failure.RuleName), color.GreenString(failure.Failure)}}))
|
|
}
|
|
|
|
func (*Friendly) printFilePosition(sb *strings.Builder, failure lint.Failure) {
|
|
fmt.Fprintf(sb, " %s:%d:%d", failure.GetFilename(), failure.Position.Start.Line, failure.Position.Start.Column)
|
|
}
|
|
|
|
type statEntry struct {
|
|
name string
|
|
failures int
|
|
}
|
|
|
|
func (*Friendly) printSummary(w io.Writer, errors, warnings int) {
|
|
emoji := getWarningEmoji()
|
|
if errors > 0 {
|
|
emoji = getErrorEmoji()
|
|
}
|
|
problemsLabel := "problems"
|
|
if errors+warnings == 1 {
|
|
problemsLabel = "problem"
|
|
}
|
|
warningsLabel := "warnings"
|
|
if warnings == 1 {
|
|
warningsLabel = "warning"
|
|
}
|
|
errorsLabel := "errors"
|
|
if errors == 1 {
|
|
errorsLabel = "error"
|
|
}
|
|
str := fmt.Sprintf("%d %s (%d %s, %d %s)", errors+warnings, problemsLabel, errors, errorsLabel, warnings, warningsLabel)
|
|
if errors > 0 {
|
|
fmt.Fprintf(w, "%s %s\n\n", emoji, color.RedString(str))
|
|
return
|
|
}
|
|
if warnings > 0 {
|
|
fmt.Fprintf(w, "%s %s\n\n", emoji, color.YellowString(str))
|
|
return
|
|
}
|
|
}
|
|
|
|
func (*Friendly) printStatistics(w io.Writer, header string, stats map[string]int) {
|
|
if len(stats) == 0 {
|
|
return
|
|
}
|
|
data := make([]statEntry, 0, len(stats))
|
|
for name, total := range stats {
|
|
data = append(data, statEntry{name, total})
|
|
}
|
|
slices.SortFunc(data, func(a, b statEntry) int {
|
|
return -cmp.Compare(a.failures, b.failures)
|
|
})
|
|
formatted := [][]string{}
|
|
for _, entry := range data {
|
|
formatted = append(formatted, []string{color.GreenString(fmt.Sprintf("%d", entry.failures)), entry.name})
|
|
}
|
|
fmt.Fprintln(w, header)
|
|
fmt.Fprintln(w, table(formatted))
|
|
}
|
|
|
|
func table(rows [][]string) string {
|
|
var buf bytes.Buffer
|
|
tw := tabwriter.NewWriter(&buf, 0, 0, 2, ' ', 0)
|
|
for _, row := range rows {
|
|
tw.Write([]byte{'\t'})
|
|
for _, col := range row {
|
|
tw.Write(append([]byte(col), '\t'))
|
|
}
|
|
tw.Write([]byte{'\n'})
|
|
}
|
|
tw.Flush()
|
|
return buf.String()
|
|
}
|