Skip to content

Commit 9db6915

Browse files
committed
add doc-gen for new CLI (WIP)
1 parent 1cc6249 commit 9db6915

11 files changed

Lines changed: 187 additions & 1 deletion

File tree

cmd/internal/gen-cli-docs/main.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"mokapi/pkg/cmd/mokapi"
7+
)
8+
9+
func main() {
10+
cmd := mokapi.NewCmdMokapi(context.Background())
11+
err := cmd.GenMarkdown("./docs/cli")
12+
if err != nil {
13+
fmt.Println(err.Error())
14+
}
15+
}

pkg/cli/command.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
type Command struct {
1010
Name string
11+
Use string
1112
Short string
1213
Long string
1314
Example string

pkg/cli/docs.go

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
package cli
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"path/filepath"
7+
"strings"
8+
)
9+
10+
const markdownExtension = ".md"
11+
12+
func (c *Command) GenMarkdown(dir string) error {
13+
basename := strings.ReplaceAll(c.Name, " ", "_") + markdownExtension
14+
filename := filepath.Join(dir, basename)
15+
f, err := os.Create(filename)
16+
if err != nil {
17+
return err
18+
}
19+
defer f.Close()
20+
21+
if err = writeCommand(c, f); err != nil {
22+
return err
23+
}
24+
25+
return nil
26+
}
27+
28+
func writeCommand(c *Command, f *os.File) error {
29+
if _, err := f.WriteString(fmt.Sprintf("# %s\n\n", c.Name)); err != nil {
30+
return err
31+
}
32+
33+
if _, err := f.WriteString(fmt.Sprintf("> %s\n\n", c.Short)); err != nil {
34+
return err
35+
}
36+
37+
if c.Long != "" {
38+
if _, err := f.WriteString(fmt.Sprintf("## Description\n\n %s\n\n", c.Long)); err != nil {
39+
return err
40+
}
41+
}
42+
43+
if c.Use != "" {
44+
use := fmt.Sprintf("```bash\n%s\n```\n\n", c.Use)
45+
if _, err := f.WriteString(fmt.Sprintf("## Usage\n\n%s\n\n", use)); err != nil {
46+
return err
47+
}
48+
}
49+
50+
flags := map[*Flag]bool{}
51+
flagList := []*Flag{}
52+
_ = c.Flags().Visit(func(flag *Flag) error {
53+
_, ok := flags[flag]
54+
if !ok {
55+
flags[flag] = true
56+
flagList = append(flagList, flag)
57+
}
58+
return nil
59+
})
60+
if len(flags) > 0 {
61+
s, err := renderlags(flagList)
62+
if err != nil {
63+
return err
64+
}
65+
if _, err = f.WriteString(s); err != nil {
66+
return err
67+
}
68+
}
69+
70+
return nil
71+
}
72+
73+
func renderlags(flags []*Flag) (string, error) {
74+
type key struct {
75+
group string
76+
subgroup string
77+
}
78+
79+
m := map[key][]*Flag{}
80+
groups := []key{}
81+
82+
for _, f := range flags {
83+
g, sg := splitFlagName(f.Name)
84+
k := key{g, sg}
85+
m[k] = append(m[k], f)
86+
groups = append(groups, k)
87+
}
88+
89+
var sb strings.Builder
90+
currentGroup := ""
91+
for _, g := range groups {
92+
93+
if g.group != currentGroup {
94+
if _, err := sb.WriteString(fmt.Sprintf("### %s\n\n", g.group)); err != nil {
95+
return "", err
96+
}
97+
currentGroup = g.group
98+
}
99+
100+
if g.subgroup != "" {
101+
if _, err := sb.WriteString(fmt.Sprintf("#### %s\n\n", g.subgroup)); err != nil {
102+
return "", err
103+
}
104+
}
105+
106+
if _, err := sb.WriteString(`| Flag | Shorthand | Type | Default | Usage |
107+
|------|-----------|------|---------|-------|
108+
`,
109+
); err != nil {
110+
return "", err
111+
}
112+
for _, flag := range m[g] {
113+
short := flag.Shorthand
114+
if short == "" {
115+
short = "-"
116+
} else {
117+
short = "-" + short
118+
}
119+
defaultValue := "-"
120+
if flag.DefaultValue != nil && flag.DefaultValue != "" {
121+
defaultValue = fmt.Sprintf("%v", flag.DefaultValue)
122+
}
123+
if _, err := sb.WriteString(fmt.Sprintf("| --%s | %s | %s | %s | %s |\n", flag.Name, short, flag.Value.Type(), defaultValue, flag.Usage)); err != nil {
124+
return "", err
125+
}
126+
}
127+
if _, err := sb.WriteString("\n"); err != nil {
128+
return "", err
129+
}
130+
}
131+
132+
return sb.String(), nil
133+
}
134+
135+
func splitFlagName(name string) (group, subgroup string) {
136+
parts := strings.Split(name, "-")
137+
138+
switch len(parts) {
139+
case 1:
140+
return "General", ""
141+
default:
142+
return caser.String(parts[0]), caser.String(parts[1])
143+
}
144+
}

pkg/cli/flag_bool.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ func (b *boolFlag) IsSet() bool {
3434
return b.isSet
3535
}
3636

37+
func (*boolFlag) Type() string {
38+
return "bool"
39+
}
40+
3741
func (b *boolFlag) String() string {
3842
return fmt.Sprintf("%v", b.value)
3943
}

pkg/cli/flag_file.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ func (f *fileFlag) IsSet() bool {
2424
return f.isSet
2525
}
2626

27+
func (f *fileFlag) Type() string {
28+
return "file"
29+
}
30+
2731
func (f *fileFlag) String() string {
2832
return fmt.Sprintf("%v", f.value)
2933
}

pkg/cli/flag_float.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ func (f *floatFlag) IsSet() bool {
3333
return f.isSet
3434
}
3535

36+
func (f *floatFlag) Type() string {
37+
return "float"
38+
}
39+
3640
func (f *floatFlag) String() string {
3741
return fmt.Sprintf("%f", f.value)
3842
}

pkg/cli/flag_int.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ func (f *intFlag) IsSet() bool {
3838
return f.isSet
3939
}
4040

41+
func (f *intFlag) Type() string {
42+
return "int"
43+
}
44+
4145
func (f *intFlag) String() string {
4246
return fmt.Sprintf("%d", f.value)
4347
}

pkg/cli/flag_slice.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ func (f *stringSliceFlag) IsSet() bool {
3636
return f.isSet
3737
}
3838

39+
func (f *stringSliceFlag) Type() string {
40+
return "list"
41+
}
42+
3943
func (f *stringSliceFlag) String() string {
4044
return strings.Join(f.value, ",")
4145
}

pkg/cli/flag_string.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ func (f *stringFlag) String() string {
2929

3030
func (f *stringFlag) IsSet() bool { return f.isSet }
3131

32+
func (f *stringFlag) Type() string { return "string" }
33+
3234
func (fs *FlagSet) String(name string, defaultValue string, usage string) {
3335
fs.StringShort(name, "", defaultValue, usage)
3436
}

pkg/cli/flags.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ type Flag struct {
2020
Usage string
2121
Value Value
2222
DefaultValue any
23+
Aliases []string
2324
}
2425

2526
type DynamicFlag struct {
@@ -37,6 +38,7 @@ type Value interface {
3738
Value() any
3839
String() string
3940
IsSet() bool
41+
Type() string
4042
}
4143

4244
func (fs *FlagSet) setFlag(f *Flag) {
@@ -106,6 +108,7 @@ func (fs *FlagSet) Alias(name, alias string) {
106108
panic(fmt.Sprintf("flag '%v' does not exist", name))
107109
}
108110
fs.flags[alias] = f
111+
f.Aliases = append(f.Aliases, alias)
109112
}
110113

111114
func (fs *FlagSet) Visit(fn func(*Flag) error) error {

0 commit comments

Comments
 (0)