Remove unused commands from the development tools
Signed-off-by: Snider <snider@lt.hn>
This commit is contained in:
parent
5d4e081143
commit
e0cf77c64a
3 changed files with 0 additions and 302 deletions
|
|
@ -1,185 +0,0 @@
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"go/ast"
|
|
||||||
"go/doc"
|
|
||||||
"go/parser"
|
|
||||||
"go/token"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
|
||||||
|
|
||||||
"github.com/leaanthony/clir"
|
|
||||||
)
|
|
||||||
|
|
||||||
func AddDocGenCommand(parent *clir.Command) {
|
|
||||||
cmd := parent.NewSubCommand("docgen", "Generates Markdown documentation for the public API of the services.")
|
|
||||||
cmd.Action(func() error {
|
|
||||||
return runDocGen()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func runDocGen() error {
|
|
||||||
const pkgDir = "pkg"
|
|
||||||
const outDir = "docs/services"
|
|
||||||
|
|
||||||
if err := os.MkdirAll(outDir, 0755); err != nil {
|
|
||||||
return fmt.Errorf("failed to create output directory: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
dirs, err := os.ReadDir(pkgDir)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to read pkg directory: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, dir := range dirs {
|
|
||||||
if !dir.IsDir() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
serviceName := dir.Name()
|
|
||||||
servicePath := filepath.Join(pkgDir, serviceName)
|
|
||||||
|
|
||||||
if err := generateDocsForService(servicePath, serviceName, outDir); err != nil {
|
|
||||||
fmt.Printf("Warning: Could not generate docs for service '%s': %v\n", serviceName, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Documentation generated successfully in", outDir)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateDocsForService(servicePath, serviceName, outDir string) error {
|
|
||||||
fset := token.NewFileSet()
|
|
||||||
filter := func(info os.FileInfo) bool {
|
|
||||||
return !strings.HasSuffix(info.Name(), "_test.go")
|
|
||||||
}
|
|
||||||
pkgs, err := parser.ParseDir(fset, servicePath, filter, parser.ParseComments)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to parse directory %s: %w", servicePath, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
internalPath := filepath.Join(servicePath, "internal")
|
|
||||||
if _, err := os.Stat(internalPath); err == nil {
|
|
||||||
pkgs, err = parser.ParseDir(fset, internalPath, nil, parser.ParseComments)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to parse internal directory %s: %w", internalPath, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var pkg *ast.Package
|
|
||||||
for _, p := range pkgs {
|
|
||||||
pkg = p
|
|
||||||
break
|
|
||||||
}
|
|
||||||
if pkg == nil {
|
|
||||||
return fmt.Errorf("no package found in %s", servicePath)
|
|
||||||
}
|
|
||||||
|
|
||||||
docPkg := doc.New(pkg, "./", doc.AllDecls)
|
|
||||||
|
|
||||||
md, err := generateMarkdown(docPkg)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to generate markdown: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
outFile := filepath.Join(outDir, serviceName+".md")
|
|
||||||
return os.WriteFile(outFile, []byte(md), 0644)
|
|
||||||
}
|
|
||||||
|
|
||||||
const docTemplate = `---
|
|
||||||
title: {{ .Name }}
|
|
||||||
---
|
|
||||||
# Service: ` + "`" + `{{ .Name }}` + "`" + `
|
|
||||||
|
|
||||||
{{ .Doc }}
|
|
||||||
|
|
||||||
{{if .Consts}}
|
|
||||||
## Constants
|
|
||||||
{{range .Consts}}
|
|
||||||
` + "```go" + `
|
|
||||||
{{- range .Names }}{{ . }}{{ end }}
|
|
||||||
` + "```" + `
|
|
||||||
{{ .Doc }}
|
|
||||||
{{end}}{{end}}
|
|
||||||
|
|
||||||
{{if .Types}}
|
|
||||||
## Types
|
|
||||||
{{range .Types}}
|
|
||||||
### ` + "`" + `type {{ .Name }}` + "`" + `
|
|
||||||
` + "```go" + `
|
|
||||||
type {{ .Name }} {{.Decl | formatNode}}
|
|
||||||
` + "```" + `
|
|
||||||
{{ .Doc }}
|
|
||||||
|
|
||||||
{{if .Methods}}
|
|
||||||
#### Methods
|
|
||||||
{{range .Methods}}
|
|
||||||
- ` + "`" + `{{ .Name }}({{ .Decl.Type.Params | formatParams }}) {{ .Decl.Type.Results | formatParams }}` + "`" + `: {{ .Doc | oneLine }}
|
|
||||||
{{end}}{{end}}
|
|
||||||
|
|
||||||
{{end}}{{end}}
|
|
||||||
|
|
||||||
{{if .Funcs}}
|
|
||||||
## Functions
|
|
||||||
{{range .Funcs}}
|
|
||||||
- ` + "`" + `{{ .Name }}({{ .Decl.Type.Params | formatParams }}) {{ .Decl.Type.Results | formatParams }}` + "`" + `: {{ .Doc | oneLine }}
|
|
||||||
{{end}}{{end}}
|
|
||||||
`
|
|
||||||
|
|
||||||
func generateMarkdown(pkg *doc.Package) (string, error) {
|
|
||||||
funcMap := template.FuncMap{
|
|
||||||
"oneLine": func(s string) string {
|
|
||||||
return strings.TrimSpace(strings.Replace(s, "\n", " ", -1))
|
|
||||||
},
|
|
||||||
"formatNode": func(decl *ast.GenDecl) string {
|
|
||||||
if len(decl.Specs) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
spec := decl.Specs[0].(*ast.TypeSpec)
|
|
||||||
return nodeToString(spec.Type)
|
|
||||||
},
|
|
||||||
"formatParams": func(fieldList *ast.FieldList) string {
|
|
||||||
if fieldList == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
var params []string
|
|
||||||
for _, p := range fieldList.List {
|
|
||||||
var names []string
|
|
||||||
for _, name := range p.Names {
|
|
||||||
names = append(names, name.Name)
|
|
||||||
}
|
|
||||||
typeStr := nodeToString(p.Type)
|
|
||||||
if len(names) > 0 {
|
|
||||||
params = append(params, strings.Join(names, ", ")+" "+typeStr)
|
|
||||||
} else {
|
|
||||||
params = append(params, typeStr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return strings.Join(params, ", ")
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpl, err := template.New("doc").Funcs(funcMap).Parse(docTemplate)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
if err := tmpl.Execute(&buf, pkg); err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf.String(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func nodeToString(node ast.Node) string {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
err := ast.Fprint(&buf, token.NewFileSet(), node, nil)
|
|
||||||
if err != nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
@ -67,9 +67,7 @@ func Execute() error {
|
||||||
// Add the top-level commands
|
// Add the top-level commands
|
||||||
devCmd := app.NewSubCommand("dev", "Development tools for Core Framework")
|
devCmd := app.NewSubCommand("dev", "Development tools for Core Framework")
|
||||||
AddAPICommands(devCmd)
|
AddAPICommands(devCmd)
|
||||||
AddTestGenCommand(devCmd)
|
|
||||||
AddSyncCommand(devCmd)
|
AddSyncCommand(devCmd)
|
||||||
AddDocGenCommand(devCmd)
|
|
||||||
AddBuildCommand(app)
|
AddBuildCommand(app)
|
||||||
AddTviewCommand(app)
|
AddTviewCommand(app)
|
||||||
// Run the application
|
// Run the application
|
||||||
|
|
|
||||||
|
|
@ -1,115 +0,0 @@
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"text/template"
|
|
||||||
|
|
||||||
"github.com/leaanthony/clir"
|
|
||||||
"golang.org/x/text/cases"
|
|
||||||
"golang.org/x/text/language"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AddTestGenCommand adds the 'test-gen' command to the given parent command.
|
|
||||||
func AddTestGenCommand(parent *clir.Command) {
|
|
||||||
testGenCmd := parent.NewSubCommand("test-gen", "Generates baseline test files for public service APIs.")
|
|
||||||
testGenCmd.LongDescription("This command scans for public services and generates a standard set of API contract tests for each one.")
|
|
||||||
testGenCmd.Action(func() error {
|
|
||||||
if err := runTestGen(); err != nil {
|
|
||||||
return fmt.Errorf("Error during test generation: %w", err)
|
|
||||||
}
|
|
||||||
fmt.Println("API test files generated successfully.")
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const testFileTemplate = `package {{.ServiceName}}_test
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/Snider/Core/{{.ServiceName}}"
|
|
||||||
"github.com/Snider/Core/pkg/core"
|
|
||||||
)
|
|
||||||
|
|
||||||
// TestNew ensures that the public constructor New is available.
|
|
||||||
func TestNew(t *testing.T) {
|
|
||||||
if {{.ServiceName}}.New == nil {
|
|
||||||
t.Fatal("{{.ServiceName}}.New constructor is nil")
|
|
||||||
}
|
|
||||||
// Note: This is a basic check. Some services may require a core instance
|
|
||||||
// or other arguments. This test can be expanded as needed.
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestRegister ensures that the public factory Register is available.
|
|
||||||
func TestRegister(t *testing.T) {
|
|
||||||
if {{.ServiceName}}.Register == nil {
|
|
||||||
t.Fatal("{{.ServiceName}}.Register factory is nil")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestInterfaceCompliance ensures that the public Service type correctly
|
|
||||||
// implements the public {{.InterfaceName}} interface. This is a compile-time check.
|
|
||||||
func TestInterfaceCompliance(t *testing.T) {
|
|
||||||
// This is a compile-time check. If it compiles, the test passes.
|
|
||||||
var _ core.{{.InterfaceName}} = (*{{.ServiceName}}.Service)(nil)
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
func runTestGen() error {
|
|
||||||
pkgDir := "pkg"
|
|
||||||
internalDirs, err := os.ReadDir(pkgDir)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to read pkg directory: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, dir := range internalDirs {
|
|
||||||
if !dir.IsDir() || dir.Name() == "core" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
serviceName := dir.Name()
|
|
||||||
publicDir := serviceName
|
|
||||||
|
|
||||||
// Check if a corresponding top-level public API directory exists.
|
|
||||||
if _, err := os.Stat(publicDir); os.IsNotExist(err) {
|
|
||||||
continue // Not a public service, so we skip it.
|
|
||||||
}
|
|
||||||
|
|
||||||
testFilePath := filepath.Join(publicDir, serviceName+"_test.go")
|
|
||||||
fmt.Printf("Generating test file for service '%s' at %s\n", serviceName, testFilePath)
|
|
||||||
|
|
||||||
if err := generateTestFile(testFilePath, serviceName); err != nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Warning: could not generate test for service '%s': %v\n", serviceName, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func generateTestFile(path, serviceName string) error {
|
|
||||||
tmpl, err := template.New("test").Parse(testFileTemplate)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
tcaser := cases.Title(language.English)
|
|
||||||
interfaceName := tcaser.String(serviceName)
|
|
||||||
|
|
||||||
data := struct {
|
|
||||||
ServiceName string
|
|
||||||
InterfaceName string
|
|
||||||
}{
|
|
||||||
ServiceName: serviceName,
|
|
||||||
InterfaceName: interfaceName,
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
if err := tmpl.Execute(&buf, data); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return os.WriteFile(path, buf.Bytes(), 0644)
|
|
||||||
}
|
|
||||||
Loading…
Add table
Reference in a new issue