Skip to content

Commit 8f1642b

Browse files
committed
feat: display linters help as JSON
1 parent 127edc0 commit 8f1642b

File tree

1 file changed

+86
-28
lines changed

1 file changed

+86
-28
lines changed

pkg/commands/help.go

Lines changed: 86 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,25 @@ 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+
}
30+
31+
type helpOptions struct {
32+
JSON bool
33+
}
34+
2035
type helpCommand struct {
2136
cmd *cobra.Command
2237

38+
opts helpOptions
39+
2340
dbManager *lintersdb.Manager
2441

2542
log logutils.Log
@@ -37,16 +54,21 @@ func newHelpCommand(logger logutils.Log) *helpCommand {
3754
},
3855
}
3956

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-
)
57+
lintersCmd := &cobra.Command{
58+
Use: "linters",
59+
Short: "Help about linters",
60+
Args: cobra.NoArgs,
61+
ValidArgsFunction: cobra.NoFileCompletions,
62+
RunE: c.execute,
63+
PreRunE: c.preRunE,
64+
}
65+
66+
helpCmd.AddCommand(lintersCmd)
67+
68+
fs := lintersCmd.Flags()
69+
fs.SortFlags = false // sort them as they are defined here
70+
71+
fs.BoolVar(&c.opts.JSON, "json", true, color.GreenString("Display as JSON"))
5072

5173
c.cmd = helpCmd
5274

@@ -66,7 +88,39 @@ func (c *helpCommand) preRunE(_ *cobra.Command, _ []string) error {
6688
return nil
6789
}
6890

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

128182
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-
}
183+
desc := formatDescription(lc.Linter.Desc())
145184

146185
deprecatedMark := ""
147186
if lc.IsDeprecated() {
148187
deprecatedMark = " [" + color.RedString("deprecated") + "]"
149188
}
150189

151190
_, _ = fmt.Fprintf(logutils.StdOut, "%s%s: %s [fast: %t, auto-fix: %t]\n",
152-
color.YellowString(lc.Name()), deprecatedMark, string(rawDesc), !lc.IsSlowLinter(), lc.CanAutoFix)
191+
color.YellowString(lc.Name()), deprecatedMark, desc, !lc.IsSlowLinter(), lc.CanAutoFix)
192+
}
193+
}
194+
195+
func formatDescription(desc string) string {
196+
// If the linter description spans multiple lines, truncate everything following the first newline
197+
endFirstLine := strings.IndexRune(desc, '\n')
198+
if endFirstLine > 0 {
199+
desc = desc[:endFirstLine]
153200
}
201+
202+
rawDesc := []rune(desc)
203+
204+
r, _ := utf8.DecodeRuneInString(desc)
205+
rawDesc[0] = unicode.ToUpper(r)
206+
207+
if rawDesc[len(rawDesc)-1] != '.' {
208+
rawDesc = append(rawDesc, '.')
209+
}
210+
211+
return string(rawDesc)
154212
}

0 commit comments

Comments
 (0)