diff --git a/config.go b/config.go index b013769..a597219 100644 --- a/config.go +++ b/config.go @@ -50,6 +50,7 @@ var allRules = append([]lint.Rule{ var allFormatters = []lint.Formatter{ &formatter.Stylish{}, + &formatter.Friendly{}, &formatter.JSON{}, &formatter.Default{}, } diff --git a/config.toml b/config.toml index 553b533..b2e9572 100644 --- a/config.toml +++ b/config.toml @@ -5,6 +5,7 @@ confidence = 0.8 [rule.package-comments] [rule.else] [rule.names] + severity = "error" [rule.var-declaration] [rule.unexported-return] [rule.time-names] diff --git a/formatter/friendly.go b/formatter/friendly.go new file mode 100644 index 0000000..d625b4d --- /dev/null +++ b/formatter/friendly.go @@ -0,0 +1,111 @@ +package formatter + +import ( + "bytes" + "fmt" + "sort" + + "github.com/fatih/color" + "github.com/mgechev/revive/lint" + "github.com/olekukonko/tablewriter" +) + +var ( + errorEmoji = color.RedString("✘") + warningEmoji = color.YellowString("⚠") +) + +var newLines = map[rune]bool{ + 0x000A: true, + 0x000B: true, + 0x000C: true, + 0x000D: true, + 0x0085: true, + 0x2028: true, + 0x2029: true, +} + +// 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 (f *Friendly) Name() string { + return "friendly" +} + +// Format formats the failures gotten from the lint. +func (f *Friendly) Format(failures <-chan lint.Failure, config lint.RulesConfig) (string, error) { + errorMap := map[string]int{} + warningMap := map[string]int{} + for failure := range failures { + sev := severity(config, failure) + f.printFriendlyFailure(failure, sev) + if sev == lint.SeverityWarning { + warningMap[failure.RuleName] = warningMap[failure.RuleName] + 1 + } + if sev == lint.SeverityError { + errorMap[failure.RuleName] = errorMap[failure.RuleName] + 1 + } + } + f.printStatistics(color.RedString("Errors:"), errorMap) + f.printStatistics(color.YellowString("Warnings:"), warningMap) + return "", nil +} + +func (f *Friendly) printFriendlyFailure(failure lint.Failure, severity lint.Severity) { + f.printHeaderRow(failure, severity) + f.printFilePosition(failure) + fmt.Println() + fmt.Println() +} + +func (f *Friendly) printHeaderRow(failure lint.Failure, severity lint.Severity) { + emoji := warningEmoji + if severity == lint.SeverityError { + emoji = errorEmoji + } + fmt.Print(f.table([][]string{{emoji, failure.RuleName, color.GreenString(failure.Failure)}})) +} + +func (f *Friendly) printFilePosition(failure lint.Failure) { + fmt.Printf(" %s:%d:%d", failure.GetFilename(), failure.Position.Start.Offset, failure.Position.End.Offset) +} + +type statEntry struct { + name string + failures int +} + +func (f *Friendly) printStatistics(header string, stats map[string]int) { + if len(stats) == 0 { + return + } + var data []statEntry + for name, total := range stats { + data = append(data, statEntry{name, total}) + } + sort.Slice(data, func(i, j int) bool { + return data[i].failures > data[j].failures + }) + formatted := [][]string{} + for _, entry := range data { + formatted = append(formatted, []string{color.GreenString(fmt.Sprintf("%d", entry.failures)), entry.name}) + } + fmt.Println(header) + fmt.Println(f.table(formatted)) +} + +func (f *Friendly) table(rows [][]string) string { + buf := new(bytes.Buffer) + table := tablewriter.NewWriter(buf) + table.SetBorder(false) + table.SetColumnSeparator("") + table.SetRowSeparator("") + table.SetAutoWrapText(false) + table.AppendBulk(rows) + table.Render() + return buf.String() +} diff --git a/formatter/severity.go b/formatter/severity.go new file mode 100644 index 0000000..06ba082 --- /dev/null +++ b/formatter/severity.go @@ -0,0 +1,10 @@ +package formatter + +import "github.com/mgechev/revive/lint" + +func severity(config lint.RulesConfig, failure lint.Failure) lint.Severity { + if config, ok := config[failure.RuleName]; ok && config.Severity == lint.SeverityError { + return lint.SeverityError + } + return lint.SeverityWarning +} diff --git a/formatter/stylish.go b/formatter/stylish.go index 762933a..686c70a 100644 --- a/formatter/stylish.go +++ b/formatter/stylish.go @@ -9,11 +9,6 @@ import ( "github.com/olekukonko/tablewriter" ) -const ( - errorEmoji = "" - warningEmoji = "" -) - // Stylish is an implementation of the Formatter interface // which formats the errors to JSON. type Stylish struct { @@ -44,9 +39,8 @@ func (f *Stylish) Format(failures <-chan lint.Failure, config lint.RulesConfig) for f := range failures { total++ - currentType := lint.SeverityWarning - if config, ok := config[f.RuleName]; ok && config.Severity == lint.SeverityError { - currentType = lint.SeverityError + currentType := severity(config, f) + if currentType == lint.SeverityError { totalErrors++ } result = append(result, formatFailure(f, lint.Severity(currentType)))