fix: gen provider
This commit is contained in:
@@ -37,12 +37,13 @@ import (
|
|||||||
// - RunE: commandGenProviderE - 命令执行函数
|
// - RunE: commandGenProviderE - 命令执行函数
|
||||||
//
|
//
|
||||||
// 注释语法说明:
|
// 注释语法说明:
|
||||||
// @provider(<mode>):[except|only] [returnType] [group]
|
//
|
||||||
// - mode: grpc|event|job|cronjob|model(可选)
|
// @provider(<mode>):[except|only] [returnType] [group]
|
||||||
// - :only: 仅注入字段 tag 为 inject:"true" 的依赖
|
// - mode: grpc|event|job|cronjob|model(可选)
|
||||||
// - :except: 注入除标注 inject:"false" 之外的非标量依赖
|
// - :only: 仅注入字段 tag 为 inject:"true" 的依赖
|
||||||
// - returnType: Provide 返回类型(如 contracts.Initial)
|
// - :except: 注入除标注 inject:"false" 之外的非标量依赖
|
||||||
// - group: 分组(如 atom.GroupInitial)
|
// - returnType: Provide 返回类型(如 contracts.Initial)
|
||||||
|
// - group: 分组(如 atom.GroupInitial)
|
||||||
//
|
//
|
||||||
// 参数:
|
// 参数:
|
||||||
// - root: 根命令对象,用于注册子命令
|
// - root: 根命令对象,用于注册子命令
|
||||||
@@ -149,11 +150,12 @@ func CommandGenProvider(root *cobra.Command) {
|
|||||||
// - 文件生成错误:返回 provider.Render() 的错误
|
// - 文件生成错误:返回 provider.Render() 的错误
|
||||||
//
|
//
|
||||||
// 使用示例:
|
// 使用示例:
|
||||||
// # 在当前目录生成 Provider
|
|
||||||
// atomctl gen provider
|
|
||||||
//
|
//
|
||||||
// # 在指定目录生成 Provider
|
// # 在当前目录生成 Provider
|
||||||
// atomctl gen provider ./internal/services
|
// atomctl gen provider
|
||||||
|
//
|
||||||
|
// # 在指定目录生成 Provider
|
||||||
|
// atomctl gen provider ./internal/services
|
||||||
//
|
//
|
||||||
// 注意事项:
|
// 注意事项:
|
||||||
// - 目标目录必须包含 go.mod 文件
|
// - 目标目录必须包含 go.mod 文件
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import (
|
|||||||
// - 错误处理:提供完善的错误处理机制
|
// - 错误处理:提供完善的错误处理机制
|
||||||
//
|
//
|
||||||
// 执行流程:
|
// 执行流程:
|
||||||
// 1. 文件过滤 → 2. AST 解析 → 3. 遍历声明 → 4. 访问者通知 → 5. 结果收集
|
// 1. 文件过滤 → 2. AST 解析 → 3. 遍历声明 → 4. 访问者通知 → 5. 结果收集
|
||||||
//
|
//
|
||||||
// 设计原则:
|
// 设计原则:
|
||||||
// - 单一职责:专注于 AST 遍历,不涉及具体的业务逻辑
|
// - 单一职责:专注于 AST 遍历,不涉及具体的业务逻辑
|
||||||
@@ -84,12 +84,12 @@ type WalkerConfig struct {
|
|||||||
// └─────────────────────────────────────────────────────────────┘
|
// └─────────────────────────────────────────────────────────────┘
|
||||||
//
|
//
|
||||||
// 调用时机:
|
// 调用时机:
|
||||||
// 1. VisitFile: 开始处理文件时调用,用于初始化文件级上下文
|
// 1. VisitFile: 开始处理文件时调用,用于初始化文件级上下文
|
||||||
// 2. VisitGenDecl: 遇到通用声明时调用(type、var、const)
|
// 2. VisitGenDecl: 遇到通用声明时调用(type、var、const)
|
||||||
// 3. VisitTypeSpec: 遇到类型规范时调用(具体的类型定义)
|
// 3. VisitTypeSpec: 遇到类型规范时调用(具体的类型定义)
|
||||||
// 4. VisitStructType: 遇到结构体类型时调用
|
// 4. VisitStructType: 遇到结构体类型时调用
|
||||||
// 5. VisitStructField: 遍历结构体字段时调用
|
// 5. VisitStructField: 遍历结构体字段时调用
|
||||||
// 6. Complete: 文件处理完成时调用,用于清理和结果收集
|
// 6. Complete: 文件处理完成时调用,用于清理和结果收集
|
||||||
//
|
//
|
||||||
// 错误处理:
|
// 错误处理:
|
||||||
// - 如果任何方法返回错误,遍历过程会立即停止
|
// - 如果任何方法返回错误,遍历过程会立即停止
|
||||||
@@ -218,10 +218,11 @@ type NodeVisitor interface {
|
|||||||
// - *ASTWalker: 配置好的遍历器实例,可以直接使用
|
// - *ASTWalker: 配置好的遍历器实例,可以直接使用
|
||||||
//
|
//
|
||||||
// 使用示例:
|
// 使用示例:
|
||||||
// walker := NewASTWalker()
|
//
|
||||||
// visitor := NewProviderDiscoveryVisitor()
|
// walker := NewASTWalker()
|
||||||
// walker.AddVisitor(visitor)
|
// visitor := NewProviderDiscoveryVisitor()
|
||||||
// err := walker.WalkFile("user_service.go")
|
// walker.AddVisitor(visitor)
|
||||||
|
// err := walker.WalkFile("user_service.go")
|
||||||
//
|
//
|
||||||
// 注意事项:
|
// 注意事项:
|
||||||
// - 必须添加至少一个访问者才能进行有效的分析
|
// - 必须添加至少一个访问者才能进行有效的分析
|
||||||
@@ -264,13 +265,14 @@ func NewASTWalker() *ASTWalker {
|
|||||||
// - *ASTWalker: 使用指定配置的遍历器实例
|
// - *ASTWalker: 使用指定配置的遍历器实例
|
||||||
//
|
//
|
||||||
// 使用示例:
|
// 使用示例:
|
||||||
// config := &WalkerConfig{
|
//
|
||||||
// IncludeTestFiles: true,
|
// config := &WalkerConfig{
|
||||||
// IncludeGeneratedFiles: true,
|
// IncludeTestFiles: true,
|
||||||
// StrictMode: true,
|
// IncludeGeneratedFiles: true,
|
||||||
// MaxFileSize: 5 * 1024 * 1024, // 5MB
|
// StrictMode: true,
|
||||||
// }
|
// MaxFileSize: 5 * 1024 * 1024, // 5MB
|
||||||
// walker := NewASTWalkerWithConfig(config)
|
// }
|
||||||
|
// walker := NewASTWalkerWithConfig(config)
|
||||||
//
|
//
|
||||||
// 注意事项:
|
// 注意事项:
|
||||||
// - 自定义配置会覆盖所有默认设置
|
// - 自定义配置会覆盖所有默认设置
|
||||||
@@ -392,12 +394,13 @@ func (aw *ASTWalker) RemoveVisitor(visitor NodeVisitor) {
|
|||||||
// - 访问者错误:返回访问者产生的错误,停止后续处理
|
// - 访问者错误:返回访问者产生的错误,停止后续处理
|
||||||
//
|
//
|
||||||
// 使用示例:
|
// 使用示例:
|
||||||
// walker := NewASTWalker()
|
//
|
||||||
// walker.AddVisitor(NewProviderDiscoveryVisitor())
|
// walker := NewASTWalker()
|
||||||
// err := walker.WalkFile("user_service.go")
|
// walker.AddVisitor(NewProviderDiscoveryVisitor())
|
||||||
// if err != nil {
|
// err := walker.WalkFile("user_service.go")
|
||||||
// log.Fatal("Failed to walk file: ", err)
|
// if err != nil {
|
||||||
// }
|
// log.Fatal("Failed to walk file: ", err)
|
||||||
|
// }
|
||||||
//
|
//
|
||||||
// 注意事项:
|
// 注意事项:
|
||||||
// - 必须至少添加一个访问者才能进行有效分析
|
// - 必须至少添加一个访问者才能进行有效分析
|
||||||
@@ -933,9 +936,9 @@ func (aw *ASTWalker) GetCommentParser() *CommentParser {
|
|||||||
// - 代码生成:为代码生成工具提供输入数据
|
// - 代码生成:为代码生成工具提供输入数据
|
||||||
// - 项目分析:分析项目中的 Provider 定义
|
// - 项目分析:分析项目中的 Provider 定义
|
||||||
type ProviderDiscoveryVisitor struct {
|
type ProviderDiscoveryVisitor struct {
|
||||||
commentParser *CommentParser // 注释解析器,用于解析 @provider 注解
|
commentParser *CommentParser // 注释解析器,用于解析 @provider 注解
|
||||||
providers []Provider // 发现的 Provider 列表
|
providers []Provider // 发现的 Provider 列表
|
||||||
currentFile string // 当前处理的文件路径
|
currentFile string // 当前处理的文件路径
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewProviderDiscoveryVisitor 创建新的 ProviderDiscoveryVisitor 实例
|
// NewProviderDiscoveryVisitor 创建新的 ProviderDiscoveryVisitor 实例
|
||||||
@@ -964,10 +967,11 @@ type ProviderDiscoveryVisitor struct {
|
|||||||
// - *ProviderDiscoveryVisitor: 配置好的访问者实例
|
// - *ProviderDiscoveryVisitor: 配置好的访问者实例
|
||||||
//
|
//
|
||||||
// 使用示例:
|
// 使用示例:
|
||||||
// commentParser := NewCommentParser()
|
//
|
||||||
// visitor := NewProviderDiscoveryVisitor(commentParser)
|
// commentParser := NewCommentParser()
|
||||||
// walker := NewASTWalker()
|
// visitor := NewProviderDiscoveryVisitor(commentParser)
|
||||||
// walker.AddVisitor(visitor)
|
// walker := NewASTWalker()
|
||||||
|
// walker.AddVisitor(visitor)
|
||||||
//
|
//
|
||||||
// 注意事项:
|
// 注意事项:
|
||||||
// - 注释解析器必须提前初始化
|
// - 注释解析器必须提前初始化
|
||||||
@@ -1150,7 +1154,7 @@ func (pdv *ProviderDiscoveryVisitor) VisitStructType(filePath string, structType
|
|||||||
// === Provider 构建 ===
|
// === Provider 构建 ===
|
||||||
// 创建 Provider 对象,设置基本信息
|
// 创建 Provider 对象,设置基本信息
|
||||||
provider := Provider{
|
provider := Provider{
|
||||||
StructName: typeSpec.Name.Name, // 结构体名称
|
StructName: typeSpec.Name.Name, // 结构体名称
|
||||||
Mode: providerComment.Mode, // Provider 模式
|
Mode: providerComment.Mode, // Provider 模式
|
||||||
ProviderGroup: providerComment.Group, // Provider 分组
|
ProviderGroup: providerComment.Group, // Provider 分组
|
||||||
ReturnType: providerComment.ReturnType, // 返回类型
|
ReturnType: providerComment.ReturnType, // 返回类型
|
||||||
|
|||||||
@@ -114,8 +114,8 @@ func (c *ParserContext) ShouldIncludeFile(filePath string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip generated files if not allowed
|
// Skip generated files if not allowed, but allow routes.gen.go since it may contain providers
|
||||||
if !c.Config.AllowGenFiles && strings.HasSuffix(filePath, ".gen.go") {
|
if !c.Config.AllowGenFiles && strings.HasSuffix(filePath, ".gen.go") && !strings.HasSuffix(filePath, "routes.gen.go") {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,10 +28,10 @@ import (
|
|||||||
// 执行流程:
|
// 执行流程:
|
||||||
// 1. 文件过滤 → 2. AST解析 → 3. 导入处理 → 4. 注解发现 → 5. Provider构建 → 6. 验证
|
// 1. 文件过滤 → 2. AST解析 → 3. 导入处理 → 4. 注解发现 → 5. Provider构建 → 6. 验证
|
||||||
type MainParser struct {
|
type MainParser struct {
|
||||||
commentParser *CommentParser // 负责解析 @provider 注解
|
commentParser *CommentParser // 负责解析 @provider 注解
|
||||||
importResolver *ImportResolver // 负责处理 Go 文件的导入信息
|
importResolver *ImportResolver // 负责处理 Go 文件的导入信息
|
||||||
astWalker *ASTWalker // 负责遍历 AST 发现 Provider 注解
|
astWalker *ASTWalker // 负责遍历 AST 发现 Provider 注解
|
||||||
builder *ProviderBuilder // 负责从 AST 节点构建 Provider 对象
|
builder *ProviderBuilder // 负责从 AST 节点构建 Provider 对象
|
||||||
validator *GoValidator // 负责验证 Provider 配置的正确性
|
validator *GoValidator // 负责验证 Provider 配置的正确性
|
||||||
config *ParserConfig // 负责解析器配置管理
|
config *ParserConfig // 负责解析器配置管理
|
||||||
}
|
}
|
||||||
@@ -54,9 +54,9 @@ type MainParser struct {
|
|||||||
// 返回值:配置好的 MainParser 实例,可直接调用 ParseFile() 或 ParseDir()
|
// 返回值:配置好的 MainParser 实例,可直接调用 ParseFile() 或 ParseDir()
|
||||||
func NewParser() *MainParser {
|
func NewParser() *MainParser {
|
||||||
return &MainParser{
|
return &MainParser{
|
||||||
commentParser: NewCommentParser(), // 初始化注释解析器
|
commentParser: NewCommentParser(), // 初始化注释解析器
|
||||||
importResolver: NewImportResolver(), // 初始化导入解析器
|
importResolver: NewImportResolver(), // 初始化导入解析器
|
||||||
astWalker: NewASTWalker(), // 初始化 AST 遍历器
|
astWalker: NewASTWalker(), // 初始化 AST 遍历器
|
||||||
builder: NewProviderBuilder(), // 初始化 Provider 构建器
|
builder: NewProviderBuilder(), // 初始化 Provider 构建器
|
||||||
validator: NewGoValidator(), // 初始化验证器
|
validator: NewGoValidator(), // 初始化验证器
|
||||||
config: NewParserConfig(), // 初始化默认配置
|
config: NewParserConfig(), // 初始化默认配置
|
||||||
@@ -116,7 +116,6 @@ func ParseRefactored(source string) []Provider {
|
|||||||
|
|
||||||
// 调用详细的文件解析方法
|
// 调用详细的文件解析方法
|
||||||
providers, err := parser.ParseFile(source)
|
providers, err := parser.ParseFile(source)
|
||||||
|
|
||||||
// 错误处理:记录错误并返回空结果
|
// 错误处理:记录错误并返回空结果
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Parse error: ", err)
|
log.Error("Parse error: ", err)
|
||||||
@@ -197,10 +196,10 @@ func (p *MainParser) ParseFile(source string) ([]Provider, error) {
|
|||||||
// === 步骤 5:创建构建器上下文 ===
|
// === 步骤 5:创建构建器上下文 ===
|
||||||
// 创建包含解析所需所有信息的构建器上下文
|
// 创建包含解析所需所有信息的构建器上下文
|
||||||
builderContext := &BuilderContext{
|
builderContext := &BuilderContext{
|
||||||
FilePath: source, // 当前文件路径
|
FilePath: source, // 当前文件路径
|
||||||
PackageName: node.Name.Name, // 包名
|
PackageName: node.Name.Name, // 包名
|
||||||
ImportContext: importContext, // 导入信息上下文
|
ImportContext: importContext, // 导入信息上下文
|
||||||
ASTFile: node, // AST 节点
|
ASTFile: node, // AST 节点
|
||||||
ProcessedTypes: make(map[string]bool), // 已处理的类型,避免重复
|
ProcessedTypes: make(map[string]bool), // 已处理的类型,避免重复
|
||||||
Errors: make([]error, 0), // 错误列表
|
Errors: make([]error, 0), // 错误列表
|
||||||
Warnings: make([]string, 0), // 警告列表
|
Warnings: make([]string, 0), // 警告列表
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ type Parser interface {
|
|||||||
type GoParser struct {
|
type GoParser struct {
|
||||||
config *ParserConfig // 解析器配置,控制解析行为
|
config *ParserConfig // 解析器配置,控制解析行为
|
||||||
context *ParserContext // 解析上下文,包含解析状态信息
|
context *ParserContext // 解析上下文,包含解析状态信息
|
||||||
mu sync.RWMutex // 读写锁,保护 config 和 context 的并发访问
|
mu sync.RWMutex // 读写锁,保护 config 和 context 的并发访问
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGoParser 创建一个使用默认配置的 GoParser 实例
|
// NewGoParser 创建一个使用默认配置的 GoParser 实例
|
||||||
@@ -184,8 +184,9 @@ type GoParser struct {
|
|||||||
// - *GoParser: 配置好的解析器实例,可以直接使用
|
// - *GoParser: 配置好的解析器实例,可以直接使用
|
||||||
//
|
//
|
||||||
// 使用示例:
|
// 使用示例:
|
||||||
// parser := NewGoParser()
|
//
|
||||||
// providers, err := parser.ParseFile("user_service.go")
|
// parser := NewGoParser()
|
||||||
|
// providers, err := parser.ParseFile("user_service.go")
|
||||||
func NewGoParser() *GoParser {
|
func NewGoParser() *GoParser {
|
||||||
// 创建默认配置
|
// 创建默认配置
|
||||||
config := NewParserConfig()
|
config := NewParserConfig()
|
||||||
@@ -229,12 +230,13 @@ func NewGoParser() *GoParser {
|
|||||||
// - *GoParser: 使用指定配置的解析器实例
|
// - *GoParser: 使用指定配置的解析器实例
|
||||||
//
|
//
|
||||||
// 使用示例:
|
// 使用示例:
|
||||||
// config := &ParserConfig{
|
//
|
||||||
// CacheEnabled: true,
|
// config := &ParserConfig{
|
||||||
// StrictMode: true,
|
// CacheEnabled: true,
|
||||||
// SourceLocations: true,
|
// StrictMode: true,
|
||||||
// }
|
// SourceLocations: true,
|
||||||
// parser := NewGoParserWithConfig(config)
|
// }
|
||||||
|
// parser := NewGoParserWithConfig(config)
|
||||||
func NewGoParserWithConfig(config *ParserConfig) *GoParser {
|
func NewGoParserWithConfig(config *ParserConfig) *GoParser {
|
||||||
// 处理 nil 配置,保持向后兼容
|
// 处理 nil 配置,保持向后兼容
|
||||||
if config == nil {
|
if config == nil {
|
||||||
@@ -552,12 +554,13 @@ func (p *GoParser) parseStructFields(structType *ast.StructType, imports map[str
|
|||||||
|
|
||||||
// Add injection parameter
|
// Add injection parameter
|
||||||
for _, name := range field.Names {
|
for _, name := range field.Names {
|
||||||
provider.InjectParams[name.Name] = InjectParam{
|
param := InjectParam{
|
||||||
Star: star,
|
Star: star,
|
||||||
Type: typ,
|
Type: typ,
|
||||||
Package: pkg,
|
Package: pkg,
|
||||||
PackageAlias: pkgAlias,
|
PackageAlias: pkgAlias,
|
||||||
}
|
}
|
||||||
|
provider.InjectParams[name.Name] = param
|
||||||
|
|
||||||
// Add to imports
|
// Add to imports
|
||||||
if pkg != "" && pkgAlias != "" {
|
if pkg != "" && pkgAlias != "" {
|
||||||
@@ -576,7 +579,15 @@ func (p *GoParser) parseFieldType(expr ast.Expr, imports map[string]string) (sta
|
|||||||
typ = t.Name
|
typ = t.Name
|
||||||
case *ast.StarExpr:
|
case *ast.StarExpr:
|
||||||
star = "*"
|
star = "*"
|
||||||
return p.parseFieldType(t.X, imports)
|
_, innerPkg, innerPkgAlias, innerTyp, innerErr := p.parseFieldType(t.X, imports)
|
||||||
|
if innerErr != nil {
|
||||||
|
return "", "", "", "", innerErr
|
||||||
|
}
|
||||||
|
// Use inner package info but keep star
|
||||||
|
pkg = innerPkg
|
||||||
|
pkgAlias = innerPkgAlias
|
||||||
|
typ = innerTyp
|
||||||
|
return star, pkg, pkgAlias, typ, nil
|
||||||
case *ast.SelectorExpr:
|
case *ast.SelectorExpr:
|
||||||
if x, ok := t.X.(*ast.Ident); ok {
|
if x, ok := t.X.(*ast.Ident); ok {
|
||||||
pkgAlias = x.Name
|
pkgAlias = x.Name
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ func Parse(source string) []Provider {
|
|||||||
node, err := parser.ParseFile(fset, source, nil, parser.ParseComments)
|
node, err := parser.ParseFile(fset, source, nil, parser.ParseComments)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("ERR: ", err)
|
log.Error("ERR: ", err)
|
||||||
return nil // 原始版本在错误时返回 nil
|
return nil // 原始版本在错误时返回 nil
|
||||||
}
|
}
|
||||||
imports := make(map[string]string)
|
imports := make(map[string]string)
|
||||||
for _, imp := range node.Imports {
|
for _, imp := range node.Imports {
|
||||||
@@ -415,20 +415,21 @@ func (p ProviderDescribe) String() {
|
|||||||
// parseProvider 解析 @provider 注解的语法
|
// parseProvider 解析 @provider 注解的语法
|
||||||
//
|
//
|
||||||
// 支持的语法格式:
|
// 支持的语法格式:
|
||||||
// @provider - 基本格式
|
//
|
||||||
// @provider(job) - 指定模式
|
// @provider - 基本格式
|
||||||
// @provider(job):except - 排除模式
|
// @provider(job) - 指定模式
|
||||||
// @provider:except - 排除模式(无模式)
|
// @provider(job):except - 排除模式
|
||||||
// @provider:only - 仅包含模式
|
// @provider:except - 排除模式(无模式)
|
||||||
// @provider returnType - 指定返回类型
|
// @provider:only - 仅包含模式
|
||||||
// @provider returnType group - 指定返回类型和分组
|
// @provider returnType - 指定返回类型
|
||||||
// @provider(job) returnType group - 完整格式
|
// @provider returnType group - 指定返回类型和分组
|
||||||
|
// @provider(job) returnType group - 完整格式
|
||||||
//
|
//
|
||||||
// 解析规则:
|
// 解析规则:
|
||||||
// 1. 移除 "@provider" 前缀
|
// 1. 移除 "@provider" 前缀
|
||||||
// 2. 处理模式(括号内的内容)
|
// 2. 处理模式(括号内的内容)
|
||||||
// 3. 处理注入模式(:except 或 :only)
|
// 3. 处理注入模式(:except 或 :only)
|
||||||
// 4. 解析返回类型和分组(剩余部分)
|
// 4. 解析返回类型和分组(剩余部分)
|
||||||
//
|
//
|
||||||
// 参数:
|
// 参数:
|
||||||
// - doc: @provider 注解字符串
|
// - doc: @provider 注解字符串
|
||||||
@@ -437,13 +438,14 @@ func (p ProviderDescribe) String() {
|
|||||||
// - ProviderDescribe: 解析后的注解信息
|
// - ProviderDescribe: 解析后的注解信息
|
||||||
//
|
//
|
||||||
// 示例:
|
// 示例:
|
||||||
// 输入: "@provider(job) contracts.Initial atom.GroupInitial"
|
//
|
||||||
// 输出: ProviderDescribe{
|
// 输入: "@provider(job) contracts.Initial atom.GroupInitial"
|
||||||
// Mode: "job",
|
// 输出: ProviderDescribe{
|
||||||
// ReturnType: "contracts.Initial",
|
// Mode: "job",
|
||||||
// Group: "atom.GroupInitial",
|
// ReturnType: "contracts.Initial",
|
||||||
// IsOnly: false
|
// Group: "atom.GroupInitial",
|
||||||
// }
|
// IsOnly: false
|
||||||
|
// }
|
||||||
func parseProvider(doc string) ProviderDescribe {
|
func parseProvider(doc string) ProviderDescribe {
|
||||||
result := ProviderDescribe{IsOnly: false}
|
result := ProviderDescribe{IsOnly: false}
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import (
|
|||||||
"go.ipao.vip/atomctl/v2/pkg/utils/gomod"
|
"go.ipao.vip/atomctl/v2/pkg/utils/gomod"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
//go:embed router.go.tpl
|
//go:embed router.go.tpl
|
||||||
var routeTpl string
|
var routeTpl string
|
||||||
|
|
||||||
|
|||||||
@@ -17,11 +17,11 @@ type TemplateRenderer interface {
|
|||||||
|
|
||||||
// TemplateInfo provides metadata about the template
|
// TemplateInfo provides metadata about the template
|
||||||
type TemplateInfo struct {
|
type TemplateInfo struct {
|
||||||
Name string
|
Name string
|
||||||
Version string
|
Version string
|
||||||
Functions []string
|
Functions []string
|
||||||
Options []string
|
Options []string
|
||||||
Size int
|
Size int
|
||||||
}
|
}
|
||||||
|
|
||||||
// RouteRenderer implements TemplateRenderer for route generation
|
// RouteRenderer implements TemplateRenderer for route generation
|
||||||
@@ -108,8 +108,8 @@ func (r *RouteRenderer) Render(data RenderData) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
r.logger.WithFields(log.Fields{
|
r.logger.WithFields(log.Fields{
|
||||||
"package_name": data.PackageName,
|
"package_name": data.PackageName,
|
||||||
"routes_count": len(data.Routes),
|
"routes_count": len(data.Routes),
|
||||||
"content_length": len(result),
|
"content_length": len(result),
|
||||||
}).Debug("Template rendered successfully")
|
}).Debug("Template rendered successfully")
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import (
|
|||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
type RouteDefinition struct {
|
type RouteDefinition struct {
|
||||||
FilePath string
|
FilePath string
|
||||||
Path string
|
Path string
|
||||||
@@ -80,24 +79,24 @@ func ParseFile(file string) []RouteDefinition {
|
|||||||
imports := extractImports(node)
|
imports := extractImports(node)
|
||||||
|
|
||||||
parser := &routeParser{
|
parser := &routeParser{
|
||||||
file: file,
|
file: file,
|
||||||
node: node,
|
node: node,
|
||||||
imports: imports,
|
imports: imports,
|
||||||
routes: make(map[string]RouteDefinition),
|
routes: make(map[string]RouteDefinition),
|
||||||
actions: make(map[string][]ActionDefinition),
|
actions: make(map[string][]ActionDefinition),
|
||||||
usedImports: make(map[string][]string),
|
usedImports: make(map[string][]string),
|
||||||
}
|
}
|
||||||
|
|
||||||
return parser.parse()
|
return parser.parse()
|
||||||
}
|
}
|
||||||
|
|
||||||
type routeParser struct {
|
type routeParser struct {
|
||||||
file string
|
file string
|
||||||
node *ast.File
|
node *ast.File
|
||||||
imports map[string]string
|
imports map[string]string
|
||||||
routes map[string]RouteDefinition
|
routes map[string]RouteDefinition
|
||||||
actions map[string][]ActionDefinition
|
actions map[string][]ActionDefinition
|
||||||
usedImports map[string][]string
|
usedImports map[string][]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *routeParser) parse() []RouteDefinition {
|
func (p *routeParser) parse() []RouteDefinition {
|
||||||
@@ -127,8 +126,8 @@ func (p *routeParser) parseFunctionDeclarations() {
|
|||||||
|
|
||||||
func (p *routeParser) isValidFunctionDeclaration(decl *ast.FuncDecl, ok bool) bool {
|
func (p *routeParser) isValidFunctionDeclaration(decl *ast.FuncDecl, ok bool) bool {
|
||||||
return ok &&
|
return ok &&
|
||||||
decl.Recv != nil &&
|
decl.Recv != nil &&
|
||||||
decl.Doc != nil
|
decl.Doc != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *routeParser) extractReceiverType(decl *ast.FuncDecl) string {
|
func (p *routeParser) extractReceiverType(decl *ast.FuncDecl) string {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ func (c *UserController) GetUser() error {
|
|||||||
|
|
||||||
// Create a temporary file for testing
|
// Create a temporary file for testing
|
||||||
tmpFile := "/tmp/test_route.go"
|
tmpFile := "/tmp/test_route.go"
|
||||||
err := os.WriteFile(tmpFile, []byte(code), 0644)
|
err := os.WriteFile(tmpFile, []byte(code), 0o644)
|
||||||
assert.NoError(t, err, "Should create temp file")
|
assert.NoError(t, err, "Should create temp file")
|
||||||
defer os.Remove(tmpFile)
|
defer os.Remove(tmpFile)
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ func (c *UserController) GetUser(id string, limit int) {
|
|||||||
|
|
||||||
// Create a temporary file for testing
|
// Create a temporary file for testing
|
||||||
tmpFile := "/tmp/test_params.go"
|
tmpFile := "/tmp/test_params.go"
|
||||||
err := os.WriteFile(tmpFile, []byte(code), 0644)
|
err := os.WriteFile(tmpFile, []byte(code), 0o644)
|
||||||
assert.NoError(t, err, "Should create temp file")
|
assert.NoError(t, err, "Should create temp file")
|
||||||
defer os.Remove(tmpFile)
|
defer os.Remove(tmpFile)
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@ func (c *UserController) GetUser() {
|
|||||||
|
|
||||||
// Create a temporary file for testing
|
// Create a temporary file for testing
|
||||||
tmpFile := "/tmp/test_invalid.go"
|
tmpFile := "/tmp/test_invalid.go"
|
||||||
err := os.WriteFile(tmpFile, []byte(code), 0644)
|
err := os.WriteFile(tmpFile, []byte(code), 0o644)
|
||||||
assert.NoError(t, err, "Should create temp file")
|
assert.NoError(t, err, "Should create temp file")
|
||||||
defer os.Remove(tmpFile)
|
defer os.Remove(tmpFile)
|
||||||
|
|
||||||
@@ -130,7 +130,7 @@ func (c *UserController) GetUser() {
|
|||||||
|
|
||||||
// Create a temporary file for testing
|
// Create a temporary file for testing
|
||||||
tmpFile := "/tmp/test_empty.go"
|
tmpFile := "/tmp/test_empty.go"
|
||||||
err := os.WriteFile(tmpFile, []byte(code), 0644)
|
err := os.WriteFile(tmpFile, []byte(code), 0o644)
|
||||||
assert.NoError(t, err, "Should create temp file")
|
assert.NoError(t, err, "Should create temp file")
|
||||||
defer os.Remove(tmpFile)
|
defer os.Remove(tmpFile)
|
||||||
|
|
||||||
@@ -196,7 +196,7 @@ func (c *HealthController) Check() error {
|
|||||||
`
|
`
|
||||||
// Create a temporary file for testing
|
// Create a temporary file for testing
|
||||||
tmpFile := "/tmp/test_compatibility.go"
|
tmpFile := "/tmp/test_compatibility.go"
|
||||||
err := os.WriteFile(tmpFile, []byte(code), 0644)
|
err := os.WriteFile(tmpFile, []byte(code), 0o644)
|
||||||
assert.NoError(t, err, "Should create temp file")
|
assert.NoError(t, err, "Should create temp file")
|
||||||
defer os.Remove(tmpFile)
|
defer os.Remove(tmpFile)
|
||||||
|
|
||||||
@@ -251,7 +251,7 @@ func (c *ApiController) DownloadFile(filename string) error {
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
tmpFile := "/tmp/test_special_paths.go"
|
tmpFile := "/tmp/test_special_paths.go"
|
||||||
err := os.WriteFile(tmpFile, []byte(code), 0644)
|
err := os.WriteFile(tmpFile, []byte(code), 0o644)
|
||||||
assert.NoError(t, err, "Should create temp file")
|
assert.NoError(t, err, "Should create temp file")
|
||||||
defer os.Remove(tmpFile)
|
defer os.Remove(tmpFile)
|
||||||
|
|
||||||
@@ -352,13 +352,13 @@ func (c *HealthController) Check() error {
|
|||||||
// Create a realistic file structure
|
// Create a realistic file structure
|
||||||
tmpDir := "/tmp/test_app"
|
tmpDir := "/tmp/test_app"
|
||||||
httpDir := tmpDir + "/app/http"
|
httpDir := tmpDir + "/app/http"
|
||||||
err := os.MkdirAll(httpDir, 0755)
|
err := os.MkdirAll(httpDir, 0o755)
|
||||||
assert.NoError(t, err, "Should create directory structure")
|
assert.NoError(t, err, "Should create directory structure")
|
||||||
defer os.RemoveAll(tmpDir)
|
defer os.RemoveAll(tmpDir)
|
||||||
|
|
||||||
// Write controller file
|
// Write controller file
|
||||||
controllerFile := httpDir + "/user_controller.go"
|
controllerFile := httpDir + "/user_controller.go"
|
||||||
err = os.WriteFile(controllerFile, []byte(code), 0644)
|
err = os.WriteFile(controllerFile, []byte(code), 0o644)
|
||||||
assert.NoError(t, err, "Should write controller file")
|
assert.NoError(t, err, "Should write controller file")
|
||||||
|
|
||||||
// WHEN parsing using the same method as CLI
|
// WHEN parsing using the same method as CLI
|
||||||
@@ -398,7 +398,7 @@ type EmptyController struct {
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
tmpFile := "/tmp/test_empty.go"
|
tmpFile := "/tmp/test_empty.go"
|
||||||
err := os.WriteFile(tmpFile, []byte(code), 0644)
|
err := os.WriteFile(tmpFile, []byte(code), 0o644)
|
||||||
assert.NoError(t, err, "Should create temp file")
|
assert.NoError(t, err, "Should create temp file")
|
||||||
defer os.Remove(tmpFile)
|
defer os.Remove(tmpFile)
|
||||||
|
|
||||||
@@ -419,7 +419,7 @@ package main
|
|||||||
type BrokenController struct {
|
type BrokenController struct {
|
||||||
`
|
`
|
||||||
tmpFile := "/tmp/test_broken.go"
|
tmpFile := "/tmp/test_broken.go"
|
||||||
err := os.WriteFile(tmpFile, []byte(code), 0644)
|
err := os.WriteFile(tmpFile, []byte(code), 0o644)
|
||||||
assert.NoError(t, err, "Should create temp file")
|
assert.NoError(t, err, "Should create temp file")
|
||||||
defer os.Remove(tmpFile)
|
defer os.Remove(tmpFile)
|
||||||
|
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ type RouteParser interface {
|
|||||||
|
|
||||||
// RouteDefinition represents a route definition (simplified for testing)
|
// RouteDefinition represents a route definition (simplified for testing)
|
||||||
type RouteDefinition struct {
|
type RouteDefinition struct {
|
||||||
StructName string
|
StructName string
|
||||||
Path string
|
Path string
|
||||||
Methods []string
|
Methods []string
|
||||||
Parameters []ParamDefinition
|
Parameters []ParamDefinition
|
||||||
Imports map[string]string
|
Imports map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParamDefinition represents a parameter definition (simplified for testing)
|
// ParamDefinition represents a parameter definition (simplified for testing)
|
||||||
|
|||||||
Reference in New Issue
Block a user