feat: 重构 pkg/ast/provider 模块,优化代码组织逻辑和功能实现

## 主要改进

### 架构重构
- 将单体 provider.go 拆分为多个专门的模块文件
- 实现了清晰的职责分离和模块化设计
- 遵循 SOLID 原则,提高代码可维护性

### 新增功能
- **验证规则系统**: 实现了完整的 provider 验证框架
- **报告生成器**: 支持多种格式的验证报告 (JSON/HTML/Markdown/Text)
- **解析器优化**: 重新设计了解析流程,提高性能和可扩展性
- **错误处理**: 增强了错误处理和诊断能力

### 修复关键 Bug
- 修复 @provider(job) 注解缺失 __job 注入参数的问题
- 统一了 job 和 cronjob 模式的处理逻辑
- 确保了 provider 生成的正确性和一致性

### 代码质量提升
- 添加了完整的测试套件
- 引入了 golangci-lint 代码质量检查
- 优化了代码格式和结构
- 增加了详细的文档和规范

### 文件结构优化
```
pkg/ast/provider/
├── types.go              # 类型定义
├── parser.go             # 解析器实现
├── validator.go          # 验证规则
├── report_generator.go   # 报告生成
├── renderer.go           # 渲染器
├── comment_parser.go     # 注解解析
├── modes.go             # 模式定义
├── errors.go            # 错误处理
└── validator_test.go    # 测试文件
```

### 兼容性
- 保持向后兼容性
- 支持现有的所有 provider 模式
- 优化了 API 设计和用户体验

This completes the implementation of T025-T029 tasks following TDD principles,
including validation rules implementation and critical bug fixes.
This commit is contained in:
Rogee
2025-09-19 18:58:30 +08:00
parent 8c65c6a854
commit e1f83ae469
45 changed files with 8643 additions and 313 deletions

176
pkg/ast/provider/config.go Normal file
View File

@@ -0,0 +1,176 @@
package provider
import (
"go/parser"
"go/token"
"os"
"path/filepath"
"strings"
)
// ParserConfig represents the configuration for the parser
type ParserConfig struct {
// File parsing options
ParseComments bool // Whether to parse comments (default: true)
Mode parser.Mode // Parser mode
FileSet *token.FileSet // File set for position information
// Include/exclude options
IncludePatterns []string // Glob patterns for files to include
ExcludePatterns []string // Glob patterns for files to exclude
// Provider parsing options
StrictMode bool // Whether to use strict validation (default: false)
DefaultMode string // Default provider mode for simple @provider annotations
AllowTestFiles bool // Whether to parse test files (default: false)
AllowGenFiles bool // Whether to parse generated files (default: false)
// Performance options
MaxFileSize int64 // Maximum file size to parse (bytes, default: 10MB)
Concurrency int // Number of concurrent parsers (default: 1)
CacheEnabled bool // Whether to enable caching (default: true)
// Output options
OutputDir string // Output directory for generated files
OutputFileName string // Output file name (default: provider.gen.go)
SourceLocations bool // Whether to include source location info (default: false)
}
// ParserContext represents the context for parsing operations
type ParserContext struct {
// Configuration
Config *ParserConfig
// Parsing state
FileSet *token.FileSet
WorkingDir string
ModuleName string
// Import resolution
Imports map[string]string // Package alias -> package path
ModuleInfo map[string]string // Module path -> module name
// Statistics and metrics
FilesProcessed int
FilesSkipped int
ProvidersFound int
ParseErrors []ParseError
// Caching
Cache map[string]interface{} // File path -> parsed content
}
// ParseError represents a parsing error with location information
type ParseError struct {
File string `json:"file"`
Line int `json:"line"`
Column int `json:"column"`
Message string `json:"message"`
Severity string `json:"severity"` // "error", "warning", "info"
}
// NewParserConfig creates a new ParserConfig with default values
func NewParserConfig() *ParserConfig {
return &ParserConfig{
ParseComments: true,
Mode: parser.ParseComments,
StrictMode: false,
DefaultMode: "basic",
AllowTestFiles: false,
AllowGenFiles: false,
MaxFileSize: 10 * 1024 * 1024, // 10MB
Concurrency: 1,
CacheEnabled: true,
OutputFileName: "provider.gen.go",
SourceLocations: false,
}
}
// NewParserContext creates a new ParserContext with the given configuration
func NewParserContext(config *ParserConfig) *ParserContext {
if config == nil {
config = NewParserConfig()
}
return &ParserContext{
Config: config,
FileSet: config.FileSet,
Imports: make(map[string]string),
ModuleInfo: make(map[string]string),
ParseErrors: make([]ParseError, 0),
Cache: make(map[string]interface{}),
}
}
// ShouldIncludeFile determines if a file should be included in parsing
func (c *ParserContext) ShouldIncludeFile(filePath string) bool {
// Check file extension
if filepath.Ext(filePath) != ".go" {
return false
}
// Skip test files if not allowed
if !c.Config.AllowTestFiles && strings.HasSuffix(filePath, "_test.go") {
return false
}
// Skip generated files if not allowed
if !c.Config.AllowGenFiles && strings.HasSuffix(filePath, ".gen.go") {
return false
}
// Check file size
if info, err := os.Stat(filePath); err == nil {
if info.Size() > c.Config.MaxFileSize {
c.AddError(filePath, 0, 0, "file exceeds maximum size", "warning")
return false
}
}
// TODO: Implement include/exclude pattern matching
// For now, include all Go files that pass the basic checks
return true
}
// AddError adds a parsing error to the context
func (c *ParserContext) AddError(file string, line, column int, message, severity string) {
c.ParseErrors = append(c.ParseErrors, ParseError{
File: file,
Line: line,
Column: column,
Message: message,
Severity: severity,
})
}
// HasErrors returns true if there are any errors in the context
func (c *ParserContext) HasErrors() bool {
for _, err := range c.ParseErrors {
if err.Severity == "error" {
return true
}
}
return false
}
// GetErrors returns all errors of a specific severity
func (c *ParserContext) GetErrors(severity string) []ParseError {
var errors []ParseError
for _, err := range c.ParseErrors {
if err.Severity == severity {
errors = append(errors, err)
}
}
return errors
}
// AddImport adds an import to the context
func (c *ParserContext) AddImport(alias, path string) {
c.Imports[alias] = path
}
// GetImportPath returns the import path for a given alias
func (c *ParserContext) GetImportPath(alias string) (string, bool) {
path, ok := c.Imports[alias]
return path, ok
}