github.com/songshiyun/revive@v1.1.5-0.20220323112655-f8433a19b3c5/formatter/stylish.go (about)

     1  package formatter
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  
     7  	"github.com/fatih/color"
     8  	"github.com/olekukonko/tablewriter"
     9  	"github.com/songshiyun/revive/lint"
    10  )
    11  
    12  // Stylish is an implementation of the Formatter interface
    13  // which formats the errors to JSON.
    14  type Stylish struct {
    15  	Metadata lint.FormatterMetadata
    16  }
    17  
    18  // Name returns the name of the formatter
    19  func (f *Stylish) Name() string {
    20  	return "stylish"
    21  }
    22  
    23  func formatFailure(failure lint.Failure, severity lint.Severity) []string {
    24  	fString := color.CyanString(failure.Failure)
    25  	fName := color.RedString("https://revive.run/r#" + failure.RuleName)
    26  	lineColumn := failure.Position
    27  	pos := fmt.Sprintf("(%d, %d)", lineColumn.Start.Line, lineColumn.Start.Column)
    28  	if severity == lint.SeverityWarning {
    29  		fName = color.YellowString("https://revive.run/r#" + failure.RuleName)
    30  	}
    31  	return []string{failure.GetFilename(), pos, fName, fString}
    32  }
    33  
    34  // Format formats the failures gotten from the lint.
    35  func (f *Stylish) Format(failures <-chan lint.Failure, config lint.Config) (string, error) {
    36  	var result [][]string
    37  	totalErrors := 0
    38  	total := 0
    39  
    40  	for f := range failures {
    41  		total++
    42  		currentType := severity(config, f)
    43  		if currentType == lint.SeverityError {
    44  			totalErrors++
    45  		}
    46  		result = append(result, formatFailure(f, lint.Severity(currentType)))
    47  	}
    48  	ps := "problems"
    49  	if total == 1 {
    50  		ps = "problem"
    51  	}
    52  
    53  	fileReport := make(map[string][][]string)
    54  
    55  	for _, row := range result {
    56  		if _, ok := fileReport[row[0]]; !ok {
    57  			fileReport[row[0]] = [][]string{}
    58  		}
    59  
    60  		fileReport[row[0]] = append(fileReport[row[0]], []string{row[1], row[2], row[3]})
    61  	}
    62  
    63  	output := ""
    64  	for filename, val := range fileReport {
    65  		buf := new(bytes.Buffer)
    66  		table := tablewriter.NewWriter(buf)
    67  		table.SetBorder(false)
    68  		table.SetColumnSeparator("")
    69  		table.SetRowSeparator("")
    70  		table.SetAutoWrapText(false)
    71  		table.AppendBulk(val)
    72  		table.Render()
    73  		c := color.New(color.Underline)
    74  		output += c.SprintfFunc()(filename + "\n")
    75  		output += buf.String() + "\n"
    76  	}
    77  
    78  	suffix := fmt.Sprintf(" %d %s (%d errors) (%d warnings)", total, ps, totalErrors, total-totalErrors)
    79  
    80  	if total > 0 && totalErrors > 0 {
    81  		suffix = color.RedString("\n ✖" + suffix)
    82  	} else if total > 0 && totalErrors == 0 {
    83  		suffix = color.YellowString("\n ✖" + suffix)
    84  	} else {
    85  		suffix, output = "", ""
    86  	}
    87  
    88  	return output + suffix, nil
    89  }