17
17
package main
18
18
19
19
import (
20
+ "encoding/json"
20
21
"flag"
21
22
"fmt"
22
23
"go/parser"
@@ -27,6 +28,7 @@ import (
27
28
"path/filepath"
28
29
"sort"
29
30
"strings"
31
+ "text/template"
30
32
31
33
"github.com/uudashr/gocognit"
32
34
)
@@ -35,47 +37,53 @@ const usageDoc = `Calculate cognitive complexities of Go functions.
35
37
Usage:
36
38
gocognit [flags] <Go file or directory> ...
37
39
Flags:
38
- -over N show functions with complexity > N only and
39
- return exit code 1 if the set is non-empty
40
- -top N show the top N most complex functions only
41
- -avg show the average complexity over all functions,
42
- not depending on whether -over or -top are set
43
- -format string
44
- which format to use, supported formats: [text json json-pretty] (default "text ")
40
+ -over N show functions with complexity > N only and
41
+ return exit code 1 if the set is non-empty
42
+ -top N show the top N most complex functions only
43
+ -avg show the average complexity over all functions,
44
+ not depending on whether -over or -top are set
45
+ -json encode the output as JSON
46
+ -f format string the format to use (default "{{.PkgName}}.{{.FuncName}}:{{.Complexity}}:{{.Pos}} ")
45
47
The output fields for each line are:
48
+ {{.Complexity}} {{.PkgName}} {{.FuncName}} {{.Pos}} or equal to
46
49
<complexity> <package> <function> <file:row:column>
50
+
51
+ The struct being passed to the template is:
52
+
53
+ type Stat struct {
54
+ PkgName string
55
+ FuncName string
56
+ Complexity int
57
+ Pos token.Position
58
+ }
47
59
`
48
60
49
61
const (
50
62
defaultOverFlagVal = 0
51
63
defaultTopFlagVal = - 1
52
64
)
53
65
54
- const (
55
- textFormat = "text"
56
- jsonFormat = "json"
57
- jsonPrettyFormat = "json-pretty"
58
- )
59
-
60
- var errFormatNotDefined = fmt .Errorf ("format is not valid, use a supported format %v" , supportedFormats )
61
-
62
- var (
63
- supportedFormats = []string {
64
- textFormat , jsonFormat , jsonPrettyFormat ,
65
- }
66
-
67
- over = flag .Int ("over" , defaultOverFlagVal , "show functions with complexity > N only" )
68
- top = flag .Int ("top" , defaultTopFlagVal , "show the top N most complex functions only" )
69
- avg = flag .Bool ("avg" , false , "show the average complexity" )
70
- format = flag .String ("format" , textFormat , fmt .Sprintf ("which format to use, supported formats: %v" , supportedFormats ))
71
- )
66
+ const defaultFormat = "{{.Complexity}} {{.PkgName}} {{.FuncName}} {{.Pos}}"
72
67
73
68
func usage () {
74
69
_ , _ = fmt .Fprint (os .Stderr , usageDoc )
75
70
os .Exit (2 )
76
71
}
77
72
78
73
func main () {
74
+ var (
75
+ over int
76
+ top int
77
+ avg bool
78
+ format string
79
+ jsonEncode bool
80
+ )
81
+ flag .IntVar (& over , "over" , defaultOverFlagVal , "show functions with complexity > N only" )
82
+ flag .IntVar (& top , "top" , defaultTopFlagVal , "show the top N most complex functions only" )
83
+ flag .BoolVar (& avg , "avg" , false , "show the average complexity" )
84
+ flag .StringVar (& format , "f" , defaultFormat , "the format to use" )
85
+ flag .BoolVar (& jsonEncode , "json" , false , "encode the output as JSON" )
86
+
79
87
log .SetFlags (0 )
80
88
log .SetPrefix ("gocognit: " )
81
89
flag .Usage = usage
@@ -85,22 +93,34 @@ func main() {
85
93
usage ()
86
94
}
87
95
96
+ tmpl , err := template .New ("gocognit" ).Parse (format )
97
+ if err != nil {
98
+ log .Fatal (err )
99
+ }
100
+
88
101
stats , err := analyze (args )
89
102
if err != nil {
90
103
log .Fatal (err )
91
104
}
92
105
93
106
sort .Sort (byComplexity (stats ))
94
- written , err := writeStats (os .Stdout , stats )
107
+
108
+ filteredStats := filterStats (stats , top , over )
109
+ var written int
110
+ if jsonEncode {
111
+ written , err = writeJSONStats (os .Stdout , filteredStats )
112
+ } else {
113
+ written , err = writeTextStats (os .Stdout , filteredStats , tmpl )
114
+ }
95
115
if err != nil {
96
116
log .Fatal (err )
97
117
}
98
118
99
- if * avg {
119
+ if avg {
100
120
showAverage (stats )
101
121
}
102
122
103
- if * over > 0 && written > 0 {
123
+ if over > 0 && written > 0 {
104
124
os .Exit (1 )
105
125
}
106
126
}
@@ -172,38 +192,42 @@ func analyzeDir(dirname string, stats []gocognit.Stat) ([]gocognit.Stat, error)
172
192
return stats , nil
173
193
}
174
194
175
- func writeStats (w io.Writer , sortedStats []gocognit.Stat ) (int , error ) {
176
- var formatter gocognit.Formatter
177
- switch * format {
178
- case textFormat :
179
- formatter = gocognit .NewTextFormatter (w )
180
- case jsonFormat :
181
- formatter = gocognit .NewJsonFormatter (w , false )
182
- case jsonPrettyFormat :
183
- formatter = gocognit .NewJsonFormatter (w , true )
184
- default :
185
- return 0 , errFormatNotDefined
195
+ func writeTextStats (w io.Writer , stats []gocognit.Stat , tmpl * template.Template ) (int , error ) {
196
+ for i , stat := range stats {
197
+ if err := tmpl .Execute (w , stat ); err != nil {
198
+ return i , err
199
+ }
200
+ fmt .Fprintln (w )
186
201
}
187
202
203
+ return len (stats ), nil
204
+ }
205
+
206
+ func writeJSONStats (w io.Writer , stats []gocognit.Stat ) (int , error ) {
207
+ enc := json .NewEncoder (w )
208
+ enc .SetIndent ("" , " " )
209
+ if err := enc .Encode (stats ); err != nil {
210
+ return 0 , err
211
+ }
212
+
213
+ return len (stats ), nil
214
+ }
215
+
216
+ func filterStats (sortedStats []gocognit.Stat , top , over int ) []gocognit.Stat {
188
217
var filtered []gocognit.Stat
189
218
for i , stat := range sortedStats {
190
- if i == * top {
219
+ if i == top {
191
220
break
192
221
}
193
222
194
- if stat .Complexity <= * over {
223
+ if stat .Complexity <= over {
195
224
break
196
225
}
197
226
198
227
filtered = append (filtered , stat )
199
228
}
200
229
201
- err := formatter .Format (filtered )
202
- if err != nil {
203
- return 0 , err
204
- }
205
-
206
- return len (filtered ), nil
230
+ return filtered
207
231
}
208
232
209
233
func showAverage (stats []gocognit.Stat ) {
0 commit comments