2023-12-21 08:13:00 +00:00
|
|
|
package docs
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"embed"
|
|
|
|
"html/template"
|
2024-01-01 16:54:09 +00:00
|
|
|
"reflect"
|
|
|
|
"regexp"
|
2023-12-21 08:13:00 +00:00
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
|
2023-12-21 10:15:41 +00:00
|
|
|
wp_template "github.com/thegeeklab/wp-plugin-go/template"
|
|
|
|
|
2023-12-21 08:13:00 +00:00
|
|
|
"github.com/urfave/cli/v2"
|
|
|
|
)
|
|
|
|
|
|
|
|
type PluginArg struct {
|
|
|
|
Name string
|
|
|
|
EnvVars []string
|
|
|
|
Description string
|
|
|
|
Default string
|
2024-01-01 16:54:09 +00:00
|
|
|
Type string
|
|
|
|
Required bool
|
2023-12-21 08:13:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type CliTemplate struct {
|
|
|
|
Name string
|
|
|
|
Version string
|
|
|
|
Description string
|
|
|
|
Usage string
|
|
|
|
UsageText string
|
|
|
|
GlobalArgs []*PluginArg
|
|
|
|
}
|
|
|
|
|
|
|
|
//go:embed templates
|
|
|
|
var templateFs embed.FS
|
|
|
|
|
|
|
|
// ToMarkdown creates a markdown string for the `*App`
|
|
|
|
// The function errors if either parsing or writing of the string fails.
|
|
|
|
func ToMarkdown(app *cli.App) (string, error) {
|
|
|
|
var w bytes.Buffer
|
|
|
|
|
2023-12-21 10:15:41 +00:00
|
|
|
tpls, err := template.New("cli").Funcs(wp_template.LoadFuncMap()).ParseFS(templateFs, "**/*.tmpl")
|
2023-12-21 08:13:00 +00:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := tpls.ExecuteTemplate(&w, "markdown.md.tmpl", GetTemplateData(app)); err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return w.String(), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func GetTemplateData(app *cli.App) *CliTemplate {
|
|
|
|
return &CliTemplate{
|
|
|
|
Name: app.Name,
|
|
|
|
Version: app.Version,
|
|
|
|
Description: prepareMultilineString(app.Description),
|
|
|
|
Usage: prepareMultilineString(app.Usage),
|
|
|
|
UsageText: prepareMultilineString(app.UsageText),
|
|
|
|
GlobalArgs: prepareArgsWithValues(app.VisibleFlags()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func prepareMultilineString(s string) string {
|
|
|
|
return strings.TrimRight(
|
|
|
|
strings.TrimSpace(
|
|
|
|
strings.ReplaceAll(s, "\n", " "),
|
|
|
|
),
|
|
|
|
".\r\n\t",
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
func prepareArgsWithValues(flags []cli.Flag) []*PluginArg {
|
|
|
|
return parseFlags(flags)
|
|
|
|
}
|
|
|
|
|
|
|
|
func parseFlags(flags []cli.Flag) []*PluginArg {
|
|
|
|
args := make([]*PluginArg, 0)
|
2024-01-01 17:07:31 +00:00
|
|
|
namePrefix := "plugin_"
|
2023-12-21 08:13:00 +00:00
|
|
|
|
|
|
|
for _, f := range flags {
|
|
|
|
flag, ok := f.(cli.DocGenerationFlag)
|
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
modArg := &PluginArg{}
|
|
|
|
|
2024-01-01 17:07:31 +00:00
|
|
|
name := strings.ToLower(strings.TrimSpace(flag.GetEnvVars()[0]))
|
|
|
|
if !strings.HasPrefix(name, namePrefix) {
|
|
|
|
continue
|
|
|
|
}
|
2023-12-21 08:13:00 +00:00
|
|
|
|
2024-01-01 17:07:31 +00:00
|
|
|
modArg.Name = strings.TrimPrefix(name, namePrefix)
|
2023-12-21 08:13:00 +00:00
|
|
|
modArg.Description = flag.GetUsage()
|
|
|
|
modArg.Default = flag.GetDefaultText()
|
|
|
|
|
2024-01-01 16:54:09 +00:00
|
|
|
if rf, _ := f.(cli.RequiredFlag); ok {
|
|
|
|
modArg.Required = rf.IsRequired()
|
|
|
|
}
|
|
|
|
|
|
|
|
modArg.Type = parseType(reflect.TypeOf(f).String())
|
|
|
|
|
2023-12-21 08:13:00 +00:00
|
|
|
args = append(args, modArg)
|
|
|
|
}
|
|
|
|
|
|
|
|
sort.SliceStable(args, func(i, j int) bool {
|
|
|
|
return args[i].Name < args[j].Name
|
|
|
|
})
|
|
|
|
|
|
|
|
return args
|
|
|
|
}
|
2024-01-01 16:54:09 +00:00
|
|
|
|
|
|
|
func parseType(raw string) string {
|
|
|
|
reSlice := regexp.MustCompile(`^\*cli\.(.+?)SliceFlag$`)
|
|
|
|
if reSlice.MatchString(raw) {
|
|
|
|
return "list"
|
|
|
|
}
|
|
|
|
|
2024-01-02 20:46:32 +00:00
|
|
|
reMap := regexp.MustCompile(`^\*cli\.(.+?)MapFlag$`)
|
|
|
|
if reMap.MatchString(raw) {
|
|
|
|
return "dict"
|
|
|
|
}
|
|
|
|
|
2024-01-01 16:54:09 +00:00
|
|
|
re := regexp.MustCompile(`^\*cli\.(.+?)Flag$`)
|
|
|
|
match := re.FindStringSubmatch(raw)
|
|
|
|
|
|
|
|
if len(match) > 1 {
|
|
|
|
switch ctype := strings.ToLower(match[1]); ctype {
|
2024-01-02 20:46:32 +00:00
|
|
|
case "int", "int64", "uint", "uint64":
|
|
|
|
return "integer"
|
|
|
|
case "float64":
|
|
|
|
return "float"
|
2024-01-01 16:54:09 +00:00
|
|
|
default:
|
|
|
|
return ctype
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ""
|
|
|
|
}
|