github.com/golangci/go-tools@v0.0.0-20190318060251-af6baa5dc196/lint/lintutil/format/format.go (about)

     1  // Package format provides formatters for linter problems.
     2  package format
     3  
     4  import (
     5  	"encoding/json"
     6  	"fmt"
     7  	"go/token"
     8  	"io"
     9  	"os"
    10  	"path/filepath"
    11  	"text/tabwriter"
    12  
    13  	"github.com/golangci/go-tools/lint"
    14  )
    15  
    16  func shortPath(path string) string {
    17  	cwd, err := os.Getwd()
    18  	if err != nil {
    19  		return path
    20  	}
    21  	if rel, err := filepath.Rel(cwd, path); err == nil && len(rel) < len(path) {
    22  		return rel
    23  	}
    24  	return path
    25  }
    26  
    27  func relativePositionString(pos token.Position) string {
    28  	s := shortPath(pos.Filename)
    29  	if pos.IsValid() {
    30  		if s != "" {
    31  			s += ":"
    32  		}
    33  		s += fmt.Sprintf("%d:%d", pos.Line, pos.Column)
    34  	}
    35  	if s == "" {
    36  		s = "-"
    37  	}
    38  	return s
    39  }
    40  
    41  type Statter interface {
    42  	Stats(total, errors, warnings int)
    43  }
    44  
    45  type Formatter interface {
    46  	Format(p lint.Problem)
    47  }
    48  
    49  type Text struct {
    50  	W io.Writer
    51  }
    52  
    53  func (o Text) Format(p lint.Problem) {
    54  	fmt.Fprintf(o.W, "%v: %s\n", relativePositionString(p.Position), p.String())
    55  }
    56  
    57  type JSON struct {
    58  	W io.Writer
    59  }
    60  
    61  func severity(s lint.Severity) string {
    62  	switch s {
    63  	case lint.Error:
    64  		return "error"
    65  	case lint.Warning:
    66  		return "warning"
    67  	case lint.Ignored:
    68  		return "ignored"
    69  	}
    70  	return ""
    71  }
    72  
    73  func (o JSON) Format(p lint.Problem) {
    74  	type location struct {
    75  		File   string `json:"file"`
    76  		Line   int    `json:"line"`
    77  		Column int    `json:"column"`
    78  	}
    79  	jp := struct {
    80  		Code     string   `json:"code"`
    81  		Severity string   `json:"severity,omitempty"`
    82  		Location location `json:"location"`
    83  		Message  string   `json:"message"`
    84  	}{
    85  		Code:     p.Check,
    86  		Severity: severity(p.Severity),
    87  		Location: location{
    88  			File:   p.Position.Filename,
    89  			Line:   p.Position.Line,
    90  			Column: p.Position.Column,
    91  		},
    92  		Message: p.Text,
    93  	}
    94  	_ = json.NewEncoder(o.W).Encode(jp)
    95  }
    96  
    97  type Stylish struct {
    98  	W io.Writer
    99  
   100  	prevFile string
   101  	tw       *tabwriter.Writer
   102  }
   103  
   104  func (o *Stylish) Format(p lint.Problem) {
   105  	if p.Position.Filename == "" {
   106  		p.Position.Filename = "-"
   107  	}
   108  
   109  	if p.Position.Filename != o.prevFile {
   110  		if o.prevFile != "" {
   111  			o.tw.Flush()
   112  			fmt.Fprintln(o.W)
   113  		}
   114  		fmt.Fprintln(o.W, p.Position.Filename)
   115  		o.prevFile = p.Position.Filename
   116  		o.tw = tabwriter.NewWriter(o.W, 0, 4, 2, ' ', 0)
   117  	}
   118  	fmt.Fprintf(o.tw, "  (%d, %d)\t%s\t%s\n", p.Position.Line, p.Position.Column, p.Check, p.Text)
   119  }
   120  
   121  func (o *Stylish) Stats(total, errors, warnings int) {
   122  	if o.tw != nil {
   123  		o.tw.Flush()
   124  		fmt.Fprintln(o.W)
   125  	}
   126  	fmt.Fprintf(o.W, " ✖ %d problems (%d errors, %d warnings)\n",
   127  		total, errors, warnings)
   128  }