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