Skip to content

Commit a27f475

Browse files
authored
feat: display linters help as JSON (#5209)
1 parent 97987f9 commit a27f475

File tree

1 file changed

+90
-28
lines changed

1 file changed

+90
-28
lines changed

pkg/commands/help.go

Lines changed: 90 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package commands
22

33
import (
4+
"encoding/json"
45
"fmt"
56
"slices"
67
"sort"
@@ -17,9 +18,27 @@ import (
1718
"github.com/golangci/golangci-lint/pkg/logutils"
1819
)
1920

21+
type linterHelp struct {
22+
Name string `json:"name"`
23+
Desc string `json:"description"`
24+
Fast bool `json:"fast"`
25+
AutoFix bool `json:"autoFix"`
26+
Presets []string `json:"presets"`
27+
EnabledByDefault bool `json:"enabledByDefault"`
28+
Deprecated bool `json:"deprecated"`
29+
Since string `json:"since"`
30+
OriginalURL string `json:"originalURL,omitempty"`
31+
}
32+
33+
type helpOptions struct {
34+
JSON bool
35+
}
36+
2037
type helpCommand struct {
2138
cmd *cobra.Command
2239

40+
opts helpOptions
41+
2342
dbManager *lintersdb.Manager
2443

2544
log logutils.Log
@@ -37,16 +56,21 @@ func newHelpCommand(logger logutils.Log) *helpCommand {
3756
},
3857
}
3958

40-
helpCmd.AddCommand(
41-
&cobra.Command{
42-
Use: "linters",
43-
Short: "Help about linters",
44-
Args: cobra.NoArgs,
45-
ValidArgsFunction: cobra.NoFileCompletions,
46-
Run: c.execute,
47-
PreRunE: c.preRunE,
48-
},
49-
)
59+
lintersCmd := &cobra.Command{
60+
Use: "linters",
61+
Short: "Help about linters",
62+
Args: cobra.NoArgs,
63+
ValidArgsFunction: cobra.NoFileCompletions,
64+
RunE: c.execute,
65+
PreRunE: c.preRunE,
66+
}
67+
68+
helpCmd.AddCommand(lintersCmd)
69+
70+
fs := lintersCmd.Flags()
71+
fs.SortFlags = false // sort them as they are defined here
72+
73+
fs.BoolVar(&c.opts.JSON, "json", false, color.GreenString("Display as JSON"))
5074

5175
c.cmd = helpCmd
5276

@@ -66,7 +90,41 @@ func (c *helpCommand) preRunE(_ *cobra.Command, _ []string) error {
6690
return nil
6791
}
6892

69-
func (c *helpCommand) execute(_ *cobra.Command, _ []string) {
93+
func (c *helpCommand) execute(_ *cobra.Command, _ []string) error {
94+
if c.opts.JSON {
95+
return c.printJSON()
96+
}
97+
98+
c.print()
99+
100+
return nil
101+
}
102+
103+
func (c *helpCommand) printJSON() error {
104+
var linters []linterHelp
105+
106+
for _, lc := range c.dbManager.GetAllSupportedLinterConfigs() {
107+
if lc.Internal {
108+
continue
109+
}
110+
111+
linters = append(linters, linterHelp{
112+
Name: lc.Name(),
113+
Desc: formatDescription(lc.Linter.Desc()),
114+
Fast: !lc.IsSlowLinter(),
115+
AutoFix: lc.CanAutoFix,
116+
Presets: lc.InPresets,
117+
EnabledByDefault: lc.EnabledByDefault,
118+
Deprecated: lc.IsDeprecated(),
119+
Since: lc.Since,
120+
OriginalURL: lc.OriginalURL,
121+
})
122+
}
123+
124+
return json.NewEncoder(c.cmd.OutOrStdout()).Encode(linters)
125+
}
126+
127+
func (c *helpCommand) print() {
70128
var enabledLCs, disabledLCs []*linter.Config
71129
for _, lc := range c.dbManager.GetAllSupportedLinterConfigs() {
72130
if lc.Internal {
@@ -126,22 +184,7 @@ func printLinters(lcs []*linter.Config) {
126184
})
127185

128186
for _, lc := range lcs {
129-
desc := lc.Linter.Desc()
130-
131-
// If the linter description spans multiple lines, truncate everything following the first newline
132-
endFirstLine := strings.IndexRune(desc, '\n')
133-
if endFirstLine > 0 {
134-
desc = desc[:endFirstLine]
135-
}
136-
137-
rawDesc := []rune(desc)
138-
139-
r, _ := utf8.DecodeRuneInString(desc)
140-
rawDesc[0] = unicode.ToUpper(r)
141-
142-
if rawDesc[len(rawDesc)-1] != '.' {
143-
rawDesc = append(rawDesc, '.')
144-
}
187+
desc := formatDescription(lc.Linter.Desc())
145188

146189
deprecatedMark := ""
147190
if lc.IsDeprecated() {
@@ -162,6 +205,25 @@ func printLinters(lcs []*linter.Config) {
162205
}
163206

164207
_, _ = fmt.Fprintf(logutils.StdOut, "%s%s: %s%s\n",
165-
color.YellowString(lc.Name()), deprecatedMark, string(rawDesc), capability)
208+
color.YellowString(lc.Name()), deprecatedMark, desc, capability)
209+
}
210+
}
211+
212+
func formatDescription(desc string) string {
213+
// If the linter description spans multiple lines, truncate everything following the first newline
214+
endFirstLine := strings.IndexRune(desc, '\n')
215+
if endFirstLine > 0 {
216+
desc = desc[:endFirstLine]
166217
}
218+
219+
rawDesc := []rune(desc)
220+
221+
r, _ := utf8.DecodeRuneInString(desc)
222+
rawDesc[0] = unicode.ToUpper(r)
223+
224+
if rawDesc[len(rawDesc)-1] != '.' {
225+
rawDesc = append(rawDesc, '.')
226+
}
227+
228+
return string(rawDesc)
167229
}

0 commit comments

Comments
 (0)