You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
159 lines
3.7 KiB
159 lines
3.7 KiB
3 days ago
|
package main
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"go/ast"
|
||
|
"go/parser"
|
||
|
"go/token"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"strings"
|
||
|
)
|
||
|
|
||
|
// ControllerCommentChecker Controller注释检查器
|
||
|
type ControllerCommentChecker struct {
|
||
|
errors []string
|
||
|
}
|
||
|
|
||
|
// NewControllerCommentChecker 创建检查器实例
|
||
|
func NewControllerCommentChecker() *ControllerCommentChecker {
|
||
|
return &ControllerCommentChecker{
|
||
|
errors: make([]string, 0),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// CheckFile 检查单个文件
|
||
|
func (c *ControllerCommentChecker) CheckFile(filePath string) error {
|
||
|
fset := token.NewFileSet()
|
||
|
node, err := parser.ParseFile(fset, filePath, nil, parser.ParseComments)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("解析文件失败: %v", err)
|
||
|
}
|
||
|
|
||
|
// 检查是否是Controller文件
|
||
|
if !strings.Contains(filePath, "controller") {
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// 遍历AST节点
|
||
|
ast.Inspect(node, func(n ast.Node) bool {
|
||
|
switch x := n.(type) {
|
||
|
case *ast.FuncDecl:
|
||
|
// 检查Controller方法
|
||
|
if c.isControllerMethod(x) {
|
||
|
c.checkMethodComments(x, filePath)
|
||
|
}
|
||
|
}
|
||
|
return true
|
||
|
})
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// isControllerMethod 判断是否是Controller方法
|
||
|
func (c *ControllerCommentChecker) isControllerMethod(fn *ast.FuncDecl) bool {
|
||
|
// 检查方法接收者
|
||
|
if fn.Recv == nil || len(fn.Recv.List) == 0 {
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
// 检查接收者类型是否包含Controller
|
||
|
recvType := fn.Recv.List[0].Type
|
||
|
if starExpr, ok := recvType.(*ast.StarExpr); ok {
|
||
|
if ident, ok := starExpr.X.(*ast.Ident); ok {
|
||
|
return strings.Contains(ident.Name, "Controller")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
// checkMethodComments 检查方法注释
|
||
|
func (c *ControllerCommentChecker) checkMethodComments(fn *ast.FuncDecl, filePath string) {
|
||
|
if fn.Doc == nil {
|
||
|
c.errors = append(c.errors, fmt.Sprintf("%s:%d 方法 %s 缺少注释", filePath, fn.Pos(), fn.Name.Name))
|
||
|
return
|
||
|
}
|
||
|
|
||
|
commentText := fn.Doc.Text()
|
||
|
requiredTags := []string{"@Summary", "@Description", "@Tags", "@Router"}
|
||
|
|
||
|
for _, tag := range requiredTags {
|
||
|
if !strings.Contains(commentText, tag) {
|
||
|
c.errors = append(c.errors, fmt.Sprintf("%s:%d 方法 %s 缺少 %s 注释", filePath, fn.Pos(), fn.Name.Name, tag))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// 检查中文描述
|
||
|
if !c.containsChinese(commentText) {
|
||
|
c.errors = append(c.errors, fmt.Sprintf("%s:%d 方法 %s 注释应包含中文描述", filePath, fn.Pos(), fn.Name.Name))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// containsChinese 检查是否包含中文字符
|
||
|
func (c *ControllerCommentChecker) containsChinese(text string) bool {
|
||
|
for _, r := range text {
|
||
|
if r >= 0x4e00 && r <= 0x9fff {
|
||
|
return true
|
||
|
}
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
// CheckDirectory 检查目录下的所有Controller文件
|
||
|
func (c *ControllerCommentChecker) CheckDirectory(dir string) error {
|
||
|
return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
if !info.IsDir() && strings.HasSuffix(path, ".go") {
|
||
|
return c.CheckFile(path)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
})
|
||
|
}
|
||
|
|
||
|
// GetErrors 获取检查错误
|
||
|
func (c *ControllerCommentChecker) GetErrors() []string {
|
||
|
return c.errors
|
||
|
}
|
||
|
|
||
|
// PrintReport 打印检查报告
|
||
|
func (c *ControllerCommentChecker) PrintReport() {
|
||
|
if len(c.errors) == 0 {
|
||
|
fmt.Println("✅ 所有Controller方法注释检查通过")
|
||
|
return
|
||
|
}
|
||
|
|
||
|
fmt.Printf("❌ 发现 %d 个注释问题:\n", len(c.errors))
|
||
|
for i, err := range c.errors {
|
||
|
fmt.Printf("%d. %s\n", i+1, err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func main() {
|
||
|
if len(os.Args) < 2 {
|
||
|
fmt.Println("用法: go run check_controller_comments.go <controller_directory>")
|
||
|
fmt.Println("示例: go run check_controller_comments.go ./internal/auth/controller")
|
||
|
os.Exit(1)
|
||
|
}
|
||
|
|
||
|
dir := os.Args[1]
|
||
|
checker := NewControllerCommentChecker()
|
||
|
|
||
|
fmt.Printf("🔍 检查目录: %s\n", dir)
|
||
|
|
||
|
if err := checker.CheckDirectory(dir); err != nil {
|
||
|
fmt.Printf("❌ 检查失败: %v\n", err)
|
||
|
os.Exit(1)
|
||
|
}
|
||
|
|
||
|
checker.PrintReport()
|
||
|
|
||
|
if len(checker.GetErrors()) > 0 {
|
||
|
os.Exit(1)
|
||
|
}
|
||
|
}
|