package api_gen import ( "fmt" "go/types" "strings" "golang.org/x/tools/go/packages" ) type APIPackage struct { PkgName string PkgPath string Files []string Endpoints []Endpoint Types map[string]types.Type Errors []ErrorDef } type Endpoint struct { Name string Method string Path string ImplName string ReqType string ResType string } type ErrorDef struct { Name string Type string } func parseAPIFiles(module string) (*APIPackage, error) { // Load the package with full type information cfg := &packages.Config{ Mode: packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles | packages.NeedImports | packages.NeedDeps | packages.NeedTypes | packages.NeedSyntax | packages.NeedTypesInfo, } // TODO hard-coded pkgs, err := packages.Load(cfg, module) if err != nil { return nil, fmt.Errorf("failed to load package: %w", err) } if len(pkgs) == 0 { return nil, fmt.Errorf("no packages found") } if packages.PrintErrors(pkgs) > 0 { return nil, fmt.Errorf("package loading had errors") } pkg := pkgs[0] apiPkg := &APIPackage{ PkgName: pkg.Name, PkgPath: pkg.PkgPath, Types: make(map[string]types.Type), } if err := extractFromPackage(pkg, apiPkg); err != nil { return nil, err } return apiPkg, nil } func extractFromPackage(pkg *packages.Package, apiPkg *APIPackage) error { scope := pkg.Types.Scope() // Extract Path_* constants and link to types for _, name := range scope.Names() { obj := scope.Lookup(name) if obj == nil { continue } if tn, ok := obj.(*types.TypeName); ok { if named, ok := tn.Type().(*types.Named); ok { apiPkg.Types[name] = named } } if c, ok := obj.(*types.Const); ok { if strings.HasPrefix(name, "Path_") { val := c.Val().String() val = strings.Trim(val, `"`) parts := strings.SplitN(val, " ", 2) if len(parts) == 2 { endpointName := strings.TrimPrefix(name, "Path_") reqTypeName := endpointName + "Req" resTypeName := endpointName + "Res" endpoint := Endpoint{ Name: endpointName, Method: parts[0], Path: parts[1], ReqType: reqTypeName, ResType: resTypeName, } apiPkg.Endpoints = append(apiPkg.Endpoints, endpoint) } } } } return nil }