github.com/haya14busa/reviewdog@v0.0.0-20180723114510-ffb00ef78fd3/parser.go (about) 1 package reviewdog 2 3 import ( 4 "encoding/xml" 5 "errors" 6 "fmt" 7 "io" 8 9 "github.com/haya14busa/errorformat" 10 "github.com/haya14busa/errorformat/fmts" 11 ) 12 13 // ParserOpt represents option to create Parser. Either FormatName or 14 // Errorformat should be specified. 15 type ParserOpt struct { 16 FormatName string 17 Errorformat []string 18 } 19 20 // NewParser returns Parser based on ParserOpt. 21 func NewParser(opt *ParserOpt) (Parser, error) { 22 name := opt.FormatName 23 24 if name != "" && len(opt.Errorformat) > 0 { 25 return nil, errors.New("you cannot specify both format name and errorformat at the same time") 26 } 27 28 if name == "checkstyle" { 29 return NewCheckStyleParser(), nil 30 } 31 // use defined errorformat 32 if name != "" { 33 efm, ok := fmts.DefinedFmts()[name] 34 if !ok { 35 return nil, fmt.Errorf("%q is not supported. consider to add new errrorformat to https://github.com/haya14busa/errorformat", name) 36 } 37 opt.Errorformat = efm.Errorformat 38 } 39 if len(opt.Errorformat) == 0 { 40 return nil, errors.New("errorformat is empty") 41 } 42 return NewErrorformatParserString(opt.Errorformat) 43 } 44 45 var _ Parser = &ErrorformatParser{} 46 47 // ErrorformatParser is errorformat parser. 48 type ErrorformatParser struct { 49 efm *errorformat.Errorformat 50 } 51 52 // NewErrorformatParser returns a new ErrorformatParser. 53 func NewErrorformatParser(efm *errorformat.Errorformat) *ErrorformatParser { 54 return &ErrorformatParser{efm: efm} 55 } 56 57 // NewErrorformatParserString returns a new ErrorformatParser from errorformat 58 // in string representation. 59 func NewErrorformatParserString(efms []string) (*ErrorformatParser, error) { 60 efm, err := errorformat.NewErrorformat(efms) 61 if err != nil { 62 return nil, err 63 } 64 return NewErrorformatParser(efm), nil 65 } 66 67 func (p *ErrorformatParser) Parse(r io.Reader) ([]*CheckResult, error) { 68 s := p.efm.NewScanner(r) 69 var rs []*CheckResult 70 for s.Scan() { 71 e := s.Entry() 72 if e.Valid { 73 rs = append(rs, &CheckResult{ 74 Path: e.Filename, 75 Lnum: e.Lnum, 76 Col: e.Col, 77 Message: e.Text, 78 Lines: e.Lines, 79 }) 80 } 81 } 82 return rs, nil 83 } 84 85 var _ Parser = &CheckStyleParser{} 86 87 // CheckStyleParser is checkstyle parser. 88 type CheckStyleParser struct{} 89 90 // NewCheckStyleParser returns a new CheckStyleParser. 91 func NewCheckStyleParser() Parser { 92 return &CheckStyleParser{} 93 } 94 95 func (p *CheckStyleParser) Parse(r io.Reader) ([]*CheckResult, error) { 96 var cs = new(CheckStyleResult) 97 if err := xml.NewDecoder(r).Decode(cs); err != nil { 98 return nil, err 99 } 100 var rs []*CheckResult 101 for _, file := range cs.Files { 102 for _, cerr := range file.Errors { 103 rs = append(rs, &CheckResult{ 104 Path: file.Name, 105 Lnum: cerr.Line, 106 Col: cerr.Column, 107 Message: cerr.Message, 108 Lines: []string{ 109 fmt.Sprintf("%v:%d:%d: %v: %v (%v)", 110 file.Name, cerr.Line, cerr.Column, cerr.Severity, cerr.Message, cerr.Source), 111 }, 112 }) 113 } 114 } 115 return rs, nil 116 } 117 118 // CheckStyleResult represents checkstyle XML result. 119 // <?xml version="1.0" encoding="utf-8"?><checkstyle version="4.3"><file ...></file>...</checkstyle> 120 // 121 // References: 122 // - http://checkstyle.sourceforge.net/ 123 // - http://eslint.org/docs/user-guide/formatters/#checkstyle 124 type CheckStyleResult struct { 125 XMLName xml.Name `xml:"checkstyle"` 126 Version string `xml:"version,attr"` 127 Files []*CheckStyleFile `xml:"file,omitempty"` 128 } 129 130 // CheckStyleFile represents <file name="fname"><error ... />...</file> 131 type CheckStyleFile struct { 132 Name string `xml:"name,attr"` 133 Errors []*CheckStyleError `xml:"error"` 134 } 135 136 // CheckStyleError represents <error line="1" column="10" severity="error" message="msg" source="src" /> 137 type CheckStyleError struct { 138 Column int `xml:"column,attr,omitempty"` 139 Line int `xml:"line,attr"` 140 Message string `xml:"message,attr"` 141 Severity string `xml:"severity,attr,omitempty"` 142 Source string `xml:"source,attr,omitempty"` 143 }