astp

package
v2.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 10, 2026 License: MIT Imports: 17 Imported by: 0

README

astp

Golang AST 语法树解析库,用于解析 Go 源代码生成结构化描述数据,支持在运行时查询代码信息(包括注释、Tag 等运行时不存在的信息)。

特性

  • 解析结构体、接口、函数、变量、常量、枚举
  • 支持泛型类型
  • 解析 struct tag
  • 解析注释中的 @xxx 注解
  • 支持类型引用解析
  • 支持 go.mod 模块路径解析
  • JSON 格式输出

安装

go get github.com/linxlib/astp

快速开始

1. 生成描述数据
命令行方式
# 安装命令行工具
go install github.com/linxlib/astp/cmd/astp@latest

# 解析项目(包含私有成员)
astp /path/to/project

# 仅解析导出成员
astp -exported /path/to/project

# 指定输出文件
astp -o custom.json /path/to/project
代码方式
package main

import "github.com/linxlib/astp"

func main() {
    // 创建生成器
    g := astp.NewGenerator()
    
    // 设置仅解析导出成员
    g.ExportedOnly = true
    
    // 生成描述数据
    err := g.Generate("/path/to/project", "")
    if err != nil {
        panic(err)
    }
    // 默认输出到 /path/to/project/.astp.json
}
2. 加载描述数据
package main

import "github.com/linxlib/astp"

func main() {
    // 从目录加载(查找 .astp.json)
    project, err := astp.Load("/path/to/project")
    if err != nil {
        panic(err)
    }
    
    // 或从指定文件加载
    project, err = astp.Load("/path/to/project/custom.json")
    if err != nil {
        panic(err)
    }
    
    // 创建查询器
    query := astp.NewQuery(project)
}

查询 API

类型查询
// 按名称查找类型
user := query.FindType("User")

// 按包路径和名称查找
user := query.FindTypeByPath("github.com/myproject/models", "User")

// 获取结构体
user := query.GetStruct("User")

// 获取接口
reader := query.GetInterface("Reader")

// 列出包下所有类型
types := query.ListTypes("github.com/myproject/models")
函数查询
// 按名称查找函数
fn := query.FindFunc("CreateUser")

// 获取方法的参数和返回值类型
params, results := query.GetMethodParams(method)
类型引用解析

当函数参数或字段类型是结构体时,可以解析出完整的类型信息:

// 解析 TypeRef 为完整类型
resolvedType := query.ResolveTypeRef(param.Type)

// 解析参数类型
resolvedType := query.ResolveParamType(param)

// 解析字段类型
resolvedType := query.ResolveFieldType(field)

示例:

// 假设有方法: func (u *User) Copy() *User
method := user.Methods[0]

// 获取返回值类型
returnType := method.Results[0].Type
// returnType.Name = "User", 但没有字段信息

// 解析完整类型
resolved := query.ResolveTypeRef(returnType)
// resolved.Name = "User"
// resolved.Fields = [...完整的字段列表]
// resolved.Methods = [...完整的方法列表]
注解查询

代码中的 @xxx 注解会被自动解析:

// @Service
// @Route("/api")
type UserService struct {}

// 查找带有 @Service 注解的类型
types := query.FindTypesByAnnotation("Service")

// 查找带有 @GET 注解的函数/方法
funcs := query.FindFuncsByAnnotation("GET")

// 检查类型是否有某个注解
if astp.HasAnnotation(userType.Doc, "Service") {
    // ...
}

// 获取注解值
value := astp.GetAnnotationValue(method.Doc, "Route")  // "/api"
Tag 查询
type User struct {
    Name string `json:"name" db:"user_name"`
}

// 查找带有 json tag 的字段
fields := query.FindByTag("json")

// 查找带有特定值的 tag
fields := query.FindFieldsByTag("json", "name")

// 获取字段 tag 值
tagValue := astp.GetTag(field.Tag, "json")  // "name"

// 检查字段是否有某个 tag
if astp.HasTag(field.Tag, "db") {
    // ...
}
枚举查询
type Status int

const (
    StatusActive Status = iota
    StatusInactive
    StatusPending
)

// 查找枚举
statusEnum := query.FindEnum("Status")

// 获取枚举值
for _, v := range statusEnum.Values {
    fmt.Printf("%s = %s\n", v.Name, v.Value)
}

// 列出所有枚举
enums := query.ListEnums()

// 获取枚举值列表
values := query.GetEnumValues("Status")

数据结构

Project
type Project struct {
    Packages map[string]*Package
}
Package
type Package struct {
    Name      string
    Path      string           // 完整包路径,如 github.com/myproject/models
    Types     map[string]*Type
    Functions map[string]*Func
    Variables map[string]*Var
    Constants map[string]*Const
    Enums     map[string]*Enum
}
Type
type Type struct {
    Name    string        // 类型名称
    PkgPath string        // 包路径
    Kind    TypeKind      // struct, interface, alias, enum 等
    Fields  []*Field      // 结构体字段
    Methods []*Func       // 方法
    Generic *GenericSpec  // 泛型参数
    Doc     *CommentGroup // 文档注释
}
Func
type Func struct {
    Name    string        // 函数/方法名
    PkgPath string
    Recv    *TypeRef      // 接收者(方法)
    Params  []*Param      // 参数
    Results []*Param      // 返回值
    Generic *GenericSpec  // 泛型参数
    Doc     *CommentGroup // 文档注释
}
Field
type Field struct {
    Name     string            // 字段名
    Type     *TypeRef          // 字段类型
    Tag      map[string]string // struct tag
    Doc      *CommentGroup     // 文档注释
    Embedded bool              // 是否嵌入字段
}
Enum
type Enum struct {
    Name    string        // 枚举名称
    PkgPath string
    Type    *TypeRef      // 枚举底层类型
    Values  []*EnumValue  // 枚举值
    Doc     *CommentGroup
}

type EnumValue struct {
    Name  string
    Value string        // 枚举值
    Doc   *CommentGroup
}

输出文件示例

{
  "packages": {
    "github.com/myproject/models": {
      "name": "models",
      "path": "github.com/myproject/models",
      "types": {
        "User": {
          "name": "User",
          "pkg_path": "github.com/myproject/models",
          "kind": "struct",
          "fields": [
            {
              "name": "Name",
              "type": {"name": "string", "kind": "basic"},
              "tag": {"json": "name"}
            }
          ],
          "methods": [
            {
              "name": "GetName",
              "results": [{"type": {"name": "string", "kind": "basic"}}]
            }
          ]
        }
      },
      "enums": {
        "Status": {
          "name": "Status",
          "type": {"name": "int", "kind": "basic"},
          "values": [
            {"name": "StatusActive", "value": "iota"},
            {"name": "StatusInactive"},
            {"name": "StatusPending"}
          ]
        }
      }
    }
  }
}

注意事项

  1. go.mod 必须存在: 解析时会查找 go.mod 获取正确的模块路径,如果不存在会报错中断

  2. 私有成员过滤: 使用 -exported 选项或设置 ExportedOnly = true 可过滤掉未导出的类型、函数、字段

  3. 类型解析: TypeRef 只包含类型引用信息,使用 ResolveTypeRef() 可获取完整类型定义

  4. 循环引用: 类型之间的引用通过 TypeRef 实现,避免循环引用问题

Documentation

Index

Constants

View Source
const DefaultAutoRegOutputFile = "fw_autoreg_gen.go"
View Source
const DefaultOutputFile = ".astp.json"

Variables

This section is empty.

Functions

func Generate

func Generate(dir string) error

func GenerateToFile

func GenerateToFile(dir, outputFile string) error

func GetAnnotationValue

func GetAnnotationValue(doc *CommentGroup, name string) string

func GetTag

func GetTag(tags map[string]string, key string) string

func HasAnnotation

func HasAnnotation(doc *CommentGroup, name string) bool

func HasTag

func HasTag(tags map[string]string, key string) bool

func ParseAnnotations

func ParseAnnotations(doc *CommentGroup) []string

Types

type Annotation

type Annotation struct {
	Name string            `json:"name"`
	Raw  string            `json:"raw,omitempty"`
	Args []string          `json:"args,omitempty"`
	KV   map[string]string `json:"kv,omitempty"`
}

func GetAnnotation

func GetAnnotation(doc *CommentGroup, name string) *Annotation

func GetAnnotations

func GetAnnotations(doc *CommentGroup, name string) []*Annotation

type AutoRegGenerator

type AutoRegGenerator struct {
	ExportedOnly bool
	// contains filtered or unexported fields
}

func NewAutoRegGenerator

func NewAutoRegGenerator() *AutoRegGenerator

func (*AutoRegGenerator) Generate

func (g *AutoRegGenerator) Generate(dir string, outputFile string) error

type Comment

type Comment struct {
	Text string `json:"text"`
}

type CommentGroup

type CommentGroup struct {
	List              []*Comment    `json:"list,omitempty"`
	Annotations       []string      `json:"annotations,omitempty"`
	ParsedAnnotations []*Annotation `json:"parsed_annotations,omitempty"`
}

type Const

type Const struct {
	Name    string        `json:"name"`
	PkgPath string        `json:"pkg_path"`
	Type    *TypeRef      `json:"type,omitempty"`
	Value   string        `json:"value,omitempty"`
	Doc     *CommentGroup `json:"doc,omitempty"`
}

type Enum

type Enum struct {
	Name    string        `json:"name"`
	PkgPath string        `json:"pkg_path"`
	Type    *TypeRef      `json:"type,omitempty"`
	Values  []*EnumValue  `json:"values"`
	Doc     *CommentGroup `json:"doc,omitempty"`
}

type EnumValue

type EnumValue struct {
	Name  string        `json:"name"`
	Value string        `json:"value,omitempty"`
	Doc   *CommentGroup `json:"doc,omitempty"`
}

type Field

type Field struct {
	Name     string            `json:"name"`
	Type     *TypeRef          `json:"type"`
	Tag      map[string]string `json:"tag,omitempty"`
	Doc      *CommentGroup     `json:"doc,omitempty"`
	Embedded bool              `json:"embedded"`
}

type Func

type Func struct {
	Name       string        `json:"name"`
	PkgPath    string        `json:"pkg_path"`
	Recv       *TypeRef      `json:"recv,omitempty"`
	Params     []*Param      `json:"params,omitempty"`
	Results    []*Param      `json:"results,omitempty"`
	Generic    *GenericSpec  `json:"generic,omitempty"`
	Doc        *CommentGroup `json:"doc,omitempty"`
	Signatures []string      `json:"signatures,omitempty"`
}

type Generator

type Generator struct {
	ExportedOnly bool
	// contains filtered or unexported fields
}

func NewGenerator

func NewGenerator() *Generator

func (*Generator) Generate

func (g *Generator) Generate(dir string, outputFile string) error

type GenericArg

type GenericArg struct {
	Args []*TypeRef `json:"args"`
}

type GenericParam

type GenericParam struct {
	Name        string     `json:"name"`
	Constraints []*TypeRef `json:"constraints,omitempty"`
}

type GenericSpec

type GenericSpec struct {
	Params []*GenericParam `json:"params"`
}

type Loader

type Loader struct {
	// contains filtered or unexported fields
}

func NewLoader

func NewLoader() *Loader

func (*Loader) Load

func (l *Loader) Load(dir string) error

func (*Loader) LoadFile

func (l *Loader) LoadFile(path string) error

func (*Loader) Project

func (l *Loader) Project() *Project

type ModuleInfo

type ModuleInfo struct {
	Path string
	Dir  string
}

type Package

type Package struct {
	Name      string            `json:"name"`
	Path      string            `json:"path"`
	Types     map[string]*Type  `json:"types"`
	Functions map[string]*Func  `json:"functions"`
	Variables map[string]*Var   `json:"variables"`
	Constants map[string]*Const `json:"constants"`
	Enums     map[string]*Enum  `json:"enums,omitempty"`
}

type Param

type Param struct {
	Name string   `json:"name"`
	Type *TypeRef `json:"type"`
}

type Parser

type Parser struct {
	ExportedOnly bool
	// contains filtered or unexported fields
}

func NewParser

func NewParser() *Parser

func (*Parser) Parse

func (p *Parser) Parse(dir string) (*Project, error)

func (*Parser) ParseProject

func (p *Parser) ParseProject(rootDir string) (*Project, error)

type Project

type Project struct {
	Packages map[string]*Package `json:"packages"`
}

func Load

func Load(path string) (*Project, error)

func LoadFromBytes

func LoadFromBytes(data []byte) (*Project, error)

LoadFromBytes parses a Project from in-memory JSON data. This is typically used with go:embed to load pre-generated .astp.json without requiring the file to exist on disk.

func LoadFromReader

func LoadFromReader(r io.Reader) (*Project, error)

LoadFromReader parses a Project from an io.Reader.

type Query

type Query struct {
	// contains filtered or unexported fields
}

func NewQuery

func NewQuery(project *Project) *Query

func (*Query) FindByAnnotation

func (q *Query) FindByAnnotation(annotation string) []interface{}

func (*Query) FindByTag

func (q *Query) FindByTag(tagKey string) []*Field

func (*Query) FindEnum

func (q *Query) FindEnum(name string) *Enum

func (*Query) FindFieldsByTag

func (q *Query) FindFieldsByTag(tagKey, tagValue string) []*Field

func (*Query) FindFunc

func (q *Query) FindFunc(name string) *Func

func (*Query) FindFuncsByAnnotation

func (q *Query) FindFuncsByAnnotation(annotation string) []*Func

func (*Query) FindImplementations

func (q *Query) FindImplementations(interfaceName string) []*Type

func (*Query) FindType

func (q *Query) FindType(name string) *Type

func (*Query) FindTypeByPath

func (q *Query) FindTypeByPath(pkgPath, name string) *Type

func (*Query) FindTypesByAnnotation

func (q *Query) FindTypesByAnnotation(annotation string) []*Type

func (*Query) GetEnumValues

func (q *Query) GetEnumValues(enumName string) []*EnumValue

func (*Query) GetInterface

func (q *Query) GetInterface(name string) *Type

func (*Query) GetMethodParams

func (q *Query) GetMethodParams(method *Func) (params, results []*Type)

func (*Query) GetStruct

func (q *Query) GetStruct(name string) *Type

func (*Query) ListEnums

func (q *Query) ListEnums() []*Enum

func (*Query) ListPackages

func (q *Query) ListPackages() []string

func (*Query) ListTypes

func (q *Query) ListTypes(pkgPath string) []*Type

func (*Query) ResolveFieldType

func (q *Query) ResolveFieldType(field *Field) *Type

func (*Query) ResolveParamType

func (q *Query) ResolveParamType(param *Param) *Type

func (*Query) ResolveTypeRef

func (q *Query) ResolveTypeRef(ref *TypeRef) *Type

type Type

type Type struct {
	Name       string        `json:"name"`
	PkgPath    string        `json:"pkg_path"`
	Kind       TypeKind      `json:"kind"`
	Fields     []*Field      `json:"fields,omitempty"`
	Methods    []*Func       `json:"methods,omitempty"`
	Embedded   []*TypeRef    `json:"embedded,omitempty"`
	Implements []string      `json:"implements,omitempty"`
	Generic    *GenericSpec  `json:"generic,omitempty"`
	AliasOf    *TypeRef      `json:"alias_of,omitempty"`
	KeyType    *TypeRef      `json:"key_type,omitempty"`
	ElemType   *TypeRef      `json:"elem_type,omitempty"`
	Doc        *CommentGroup `json:"doc,omitempty"`
}

type TypeKind

type TypeKind string
const (
	KindStruct    TypeKind = "struct"
	KindInterface TypeKind = "interface"
	KindAlias     TypeKind = "alias"
	KindBasic     TypeKind = "basic"
	KindSlice     TypeKind = "slice"
	KindMap       TypeKind = "map"
	KindPointer   TypeKind = "pointer"
	KindFunc      TypeKind = "func"
	KindEnum      TypeKind = "enum"
)

type TypeRef

type TypeRef struct {
	Name     string      `json:"name,omitempty"`
	PkgPath  string      `json:"pkg_path,omitempty"`
	Kind     TypeKind    `json:"kind"`
	Generic  *GenericArg `json:"generic,omitempty"`
	KeyType  *TypeRef    `json:"key_type,omitempty"`
	ElemType *TypeRef    `json:"elem_type,omitempty"`
}

type Var

type Var struct {
	Name    string        `json:"name"`
	PkgPath string        `json:"pkg_path"`
	Type    *TypeRef      `json:"type"`
	Doc     *CommentGroup `json:"doc,omitempty"`
}

Directories

Path Synopsis
cmd
astp command
query_example command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL