bast

package module
v0.0.0-...-b6f43ed Latest Latest
Warning

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

Go to latest
Published: Sep 28, 2025 License: MIT Imports: 16 Imported by: 1

README

BAST

Go Reference

BAST is a Go package that provides a simplified intermediate representation of Go source code declarations. Built on top of Go's standard go/ast and go/types packages, BAST transforms complex AST structures into an intuitive model optimized for code analysis and generation tools.

Features

  • Simplified API: Clean, intuitive interface for accessing Go declarations without navigating complex AST structures
  • Template-Friendly: Designed specifically for use with Go's text/template package for code generation
  • Type Resolution: Automatic resolution of basic types and package imports with optional type checking
  • Modern Go Support: Full support for generics, type parameters, and modern Go language features
  • Cross-Package Analysis: Query declarations across multiple packages with unified methods
  • Flexible Loading: Support for standard Go package patterns (./..., import paths, etc.)
  • Rich Metadata: Preserve documentation, comments, and structural relationships

Quick Start

package main

import (
    "fmt"
    "log"
    
    "github.com/vedranvuk/bast"
)

func main() {
    // Load Go packages from current directory
    b, err := bast.Load(bast.Default(), "./...")
    if err != nil {
        log.Fatal(err)
    }
    
    // Find all structs across packages
    for _, pkg := range b.Packages() {
        for _, s := range pkg.Structs.Values() {
            fmt.Printf("Struct: %s.%s\n", pkg.Name, s.Name)
            
            // Print struct fields
            for _, field := range s.Fields.Values() {
                fmt.Printf("  %s %s\n", field.Name, field.Type)
            }
            
            // Print methods
            for _, method := range s.Methods() {
                fmt.Printf("  func %s(...)\n", method.Name)
            }
        }
    }
}

Use Cases

Code Generation: Generate boilerplate code, interfaces, mocks, or serialization logic from existing types.

// Find all structs implementing a specific interface pattern
structs := b.AllStructs()
for _, s := range structs {
    if hasValidateMethod(s) {
        generateValidator(s)
    }
}

API Documentation: Extract and format API documentation from source code.

// Document all public functions in a package
pkg := b.PackageByPath("github.com/myorg/mypackage")
for _, fn := range pkg.Funcs.Values() {
    if isPublic(fn.Name) {
        generateDoc(fn.Name, fn.Doc, fn.Params, fn.Results)
    }
}

Static Analysis: Analyze code patterns, dependencies, and structural relationships.

// Find all types that embed a specific struct
embedders := b.TypesOfType("mypackage", "BaseStruct")
for _, typ := range embedders {
    analyzeEmbedding(typ)
}

Refactoring Tools: Build tools that understand and transform Go code structures.

Configuration

cfg := &bast.Config{
    Dir:                ".",              // Base directory
    Tests:              true,             // Include test files
    TypeChecking:       true,             // Enable type resolution
    TypeCheckingErrors: false,            // Ignore type errors
    BuildFlags:         []string{"-tags", "integration"},
}

b, err := bast.Load(cfg, "./cmd/...", "./pkg/...")

Package Structure

BAST organizes code into a hierarchical model:

  • Bast: Root container with cross-package query methods
  • Package: Represents a Go package with its declarations
  • File: Individual source files with imports and file-level declarations
  • Declarations: Vars, Consts, Funcs, Methods, Types, Structs, Interfaces
  • Fields: Function parameters, struct fields, interface methods

Each level provides both local queries (pkg.Struct("MyType")) and global searches (b.AnyStruct("MyType")).

Type Resolution

BAST can resolve type aliases and named types to their underlying basic types:

// With type checking enabled
basicType := b.ResolveBasicType("MyIntAlias") // Returns "int"
basicType = b.ResolveBasicType("pkg.CustomString") // Returns "string"

Template Integration

BAST structures are designed to work seamlessly with Go templates:

const tmpl = `
{{range .AllStructs}}
type {{.Name}} struct {
    {{range .Fields.Values}}{{.Name}} {{.Type}}{{end}}
}
{{range .Methods}}
func ({{.Receiver.Name}} {{.Receiver.Type}}) {{.Name}}({{range .Params.Values}}{{.Name}} {{.Type}}{{end}})
{{end}}
{{end}}
`

t := template.Must(template.New("").Parse(tmpl))
t.Execute(os.Stdout, bast)

Status

Production ready. The API is stable and follows semantic versioning.

License

MIT. See LICENSE file for details.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Print

func Print(w io.Writer, bast *Bast)

Print writes a human-readable representation of bast to w using the default printer configuration.

Types

type Bast

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

Bast is the top-level type that holds parsed packages and their declarations.

It provides methods for querying and retrieving declarations across all packages.

func Load

func Load(config *Config, patterns ...string) (bast *Bast, err error)

Load loads the Go packages matching the given patterns and returns a Bast representation.

cfg configures the loading process; if nil, DefaultConfig is used.

Patterns follow the same syntax as go list or go build (e.g., "./...", "github.com/user/repo").

func (*Bast) AllConsts

func (self *Bast) AllConsts() (out []*Const)

AllConsts returns all top-level constants across all parsed packages.

func (*Bast) AllFuncs

func (self *Bast) AllFuncs() (out []*Func)

AllFuncs returns all top-level functions across all parsed packages.

func (*Bast) AllInterfaces

func (self *Bast) AllInterfaces() (out []*Interface)

AllInterfaces returns all top-level interfaces across all parsed packages.

func (*Bast) AllMethods

func (self *Bast) AllMethods() (out []*Method)

AllMethods returns all top-level methods across all parsed packages.

func (*Bast) AllPackages

func (self *Bast) AllPackages() (out []*Package)

AllPackages returns all parsed packages.

func (*Bast) AllStructs

func (self *Bast) AllStructs() (out []*Struct)

AllStructs returns all top-level structs across all parsed packages.

func (*Bast) AllTypes

func (self *Bast) AllTypes() (out []*Type)

AllTypes returns all top-level types across all parsed packages.

func (*Bast) AllVars

func (self *Bast) AllVars() (out []*Var)

AllVars returns all top-level variables across all parsed packages.

func (*Bast) AnyConst

func (self *Bast) AnyConst(declName string) (out *Const)

AnyConst returns the constant named declName from any parsed package, or nil if not found.

func (*Bast) AnyFunc

func (self *Bast) AnyFunc(declName string) (out *Func)

AnyFunc returns the function named declName from any parsed package, or nil if not found.

func (*Bast) AnyInterface

func (self *Bast) AnyInterface(declName string) (out *Interface)

AnyInterface returns the interface named declName from any parsed package, or nil if not found.

func (*Bast) AnyMethod

func (self *Bast) AnyMethod(declName string) (out *Method)

AnyMethod returns the method named declName from any parsed package, or nil if not found.

func (*Bast) AnyStruct

func (self *Bast) AnyStruct(declName string) (out *Struct)

AnyStruct returns the struct named declName from any parsed package, or nil if not found.

func (*Bast) AnyType

func (self *Bast) AnyType(declName string) (out *Type)

AnyType returns the type named declName from any parsed package, or nil if not found.

func (*Bast) AnyVar

func (self *Bast) AnyVar(declName string) (out *Var)

AnyVar returns the variable named declName from any parsed package, or nil if not found.

func (*Bast) ConstsOfType

func (self *Bast) ConstsOfType(pkgPath, typeName string) (out []*Const)

ConstsOfType returns all top-level constant declarations from the package with path pkgPath whose type matches typeName.

func (*Bast) FieldNames

func (self *Bast) FieldNames(pkgPath, structName string) (out []string)

FieldNames returns the names of the fields of the struct named structName in the package with path pkgPath.

func (*Bast) MethodSet

func (self *Bast) MethodSet(pkgPath, typeName string) (out []*Method)

MethodSet returns all methods from the package with path pkgPath whose receiver type matches typeName (with or without a pointer prefix).

func (*Bast) PackageByPath

func (self *Bast) PackageByPath(pkgPath string) (p *Package)

PackageByPath returns the package with the given import path, or nil if not found.

func (*Bast) PackageImportPaths

func (self *Bast) PackageImportPaths() []string

PackageImportPaths returns the import paths of all loaded packages.

func (*Bast) PackageNames

func (self *Bast) PackageNames() (out []string)

PackageNames returns the names of all parsed packages.

func (*Bast) Packages

func (self *Bast) Packages() []*Package

Packages returns the parsed packages.

func (*Bast) PkgConst

func (self *Bast) PkgConst(pkgPath, declName string) (out *Const)

PkgConst returns the constant named declName from the package with path pkgPath, or nil if not found.

func (*Bast) PkgConsts

func (self *Bast) PkgConsts(pkgPath string) (out []*Const)

PkgConsts returns all top-level constants in the package with path pkgPath.

func (*Bast) PkgFunc

func (self *Bast) PkgFunc(pkgPath, declName string) (out *Func)

PkgFunc returns the function named declName from the package with path pkgPath, or nil if not found.

func (*Bast) PkgFuncs

func (self *Bast) PkgFuncs(pkgPath string) (out []*Func)

PkgFuncs returns all top-level functions in the package with path pkgPath.

func (*Bast) PkgInterface

func (self *Bast) PkgInterface(pkgPath, declName string) (out *Interface)

PkgInterface returns the interface named declName from the package with path pkgPath, or nil if not found.

func (*Bast) PkgInterfaces

func (self *Bast) PkgInterfaces(pkgPath string) (out []*Interface)

PkgInterfaces returns all top-level interfaces in the package with path pkgPath.

func (*Bast) PkgMethod

func (self *Bast) PkgMethod(pkgPath, declName string) (out *Method)

PkgMethod returns the method named declName from the package with path pkgPath, or nil if not found.

func (*Bast) PkgMethods

func (self *Bast) PkgMethods(pkgPath string) (out []*Method)

PkgMethods returns all top-level methods in the package with path pkgPath.

func (*Bast) PkgStruct

func (self *Bast) PkgStruct(pkgPath, declName string) (out *Struct)

PkgStruct returns the struct named declName from the package with path pkgPath, or nil if not found.

func (*Bast) PkgStructs

func (self *Bast) PkgStructs(pkgPath string) (out []*Struct)

PkgStructs returns all top-level structs in the package with path pkgPath.

func (*Bast) PkgType

func (self *Bast) PkgType(pkgPath, declName string) (out *Type)

PkgType returns the type named declName from the package with path pkgPath, or nil if not found.

func (*Bast) PkgTypes

func (self *Bast) PkgTypes(pkgPath string) (out []*Type)

PkgTypes returns all top-level types in the package with path pkgPath.

func (*Bast) PkgVar

func (self *Bast) PkgVar(pkgPath, declName string) (out *Var)

PkgVar returns the variable named declName from the package with path pkgPath, or nil if not found.

func (*Bast) PkgVars

func (self *Bast) PkgVars(pkgPath string) (out []*Var)

PkgVars returns all top-level variables in the package with path pkgPath.

func (*Bast) ResolveBasicType

func (self *Bast) ResolveBasicType(typeName string) string

ResolveBasicType resolves the underlying basic type name for the given typeName by searching the type hierarchy of the parsed packages.

If typeName is already a basic type name, it returns typeName as is. If no basic type is found, it returns an empty string.

This method requires Config.TypeChecking to be enabled.

func (*Bast) TypesOfType

func (self *Bast) TypesOfType(pkgPath, typeName string) (out []*Type)

TypesOfType returns all top-level type declarations from the package with path pkgPath whose underlying type matches typeName.

func (*Bast) VarsOfType

func (self *Bast) VarsOfType(pkgPath, typeName string) (out []*Var)

VarsOfType returns all top-level variable declarations from the package with path pkgPath whose type matches typeName.

type Config

type Config struct {

	// Dir is the base directory for the build system's query tool.
	// If empty, the current directory is used.
	//
	// Package patterns in Load are relative to this directory.
	// Default is ".".
	Dir string `json:"dir,omitempty"`

	// BuildFlags are additional command-line flags passed to the build system's query tool.
	BuildFlags []string `json:"buildFlags,omitempty"`

	// Env is the environment variables used when invoking the build system's query tool.
	// If nil, the current environment is used.
	// Only the last value for each key is used.
	//
	// To set specific variables, append to os.Environ():
	//     opt.Env = append(os.Environ(), "GOOS=plan9", "GOARCH=386")
	Env []string `json:"env,omitempty"`

	// Tests, if true, includes related test packages when loading.
	// This includes test variants of the package and the test executable.
	Tests bool `json:"tests,omitempty"`

	// TypeChecking enables type checking during loading, required for type resolution utilities
	// like Bast.ResolveBasicType.
	// Default is true.
	TypeChecking bool `json:"typeChecking,omitempty"`

	// TypeCheckingErrors, if true, causes Load to return an error if type checking fails
	// or if any loaded package has errors.
	// Default is true.
	TypeCheckingErrors bool `json:"typeCheckingErrors,omitempty"`
}

Config configures the loading and parsing behavior of Load.

func Default

func Default() *Config

Default is an alias for DefaultConfig.

func DefaultConfig

func DefaultConfig() *Config

DefaultConfig returns a Config with default values.

type Const

type Const struct {
	Model
	// Type is the constant's type, empty if inferred.
	Type string
	// Value is the constant's value.
	Value string
}

Const represents a top-level constant declaration.

func NewConst

func NewConst(file *File, name, typ string) *Const

NewConst creates a new Const for the given file, name, and type.

type Declaration

type Declaration interface {
	// GetFile returns the declarations parent file.
	GetFile() *File
	// GetPackage returns the declarations parent package.
	GetPackage() *Package
}

Declaration is the interface implemented by all top-level declarations.

type DeclarationMap

type DeclarationMap = maps.OrderedMap[string, Declaration]

DeclarationMap is an ordered map of declarations keyed by their name in parse order.

type Field

type Field struct {
	Model

	// Type is the field's type.
	//
	// For method receivers, this is the bare type name without "*" or type parameters.
	// Use Pointer to check for pointer receivers, and inspect the parent for type parameters.
	Type string

	// Tag is the field's raw struct tag string.
	Tag string

	// Unnamed is true if the field is unnamed (embedded field).
	Unnamed bool

	// Pointer is true if this is a pointer receiver for a method.
	Pointer bool
}

Field represents a field in a struct, a parameter or result in a function, or a receiver in a method.

func NewField

func NewField(file *File, name string) *Field

NewField creates a new Field for the given file and name.

func (*Field) Clone

func (self *Field) Clone() *Field

Clone returns a copy of the field.

type FieldMap

type FieldMap = maps.OrderedMap[string, *Field]

FieldMap is an ordered map of fields keyed by name in parse order.

type File

type File struct {
	// Comments are the file comments, grouped by separation, including docs.
	Comments [][]string
	// Doc is the file doc comment.
	Doc []string
	// Name is the File name, a full file path.
	Name string
	// Imports is a list of file imports.
	Imports *ImportSpecMap
	// Declarations is a list of top level declarations in the file.
	Declarations *DeclarationMap
	// contains filtered or unexported fields
}

File represents a parsed Go source file.

It contains comments, imports, and top-level declarations.

func NewFile

func NewFile(pkg *Package, name string) *File

NewFile creates a new File for the given package and filename.

func (*File) Const

func (self *File) Const(name string) (out *Const)

Const returns the constant named name from this file, or nil if not found.

func (*File) Func

func (self *File) Func(name string) (out *Func)

Func returns the function named name from this file, or nil if not found.

func (*File) HasDecl

func (self *File) HasDecl(name string) (b bool)

HasDecl returns true if a declaration named name exists in this file.

func (*File) ImportSpecFromSelector

func (self *File) ImportSpecFromSelector(selectorExpr string) *ImportSpec

ImportSpecFromSelector returns the ImportSpec for the given selector expression (e.g., "pkg.Type"). It returns nil if the import is not found or the selector is invalid.

func (*File) Interface

func (self *File) Interface(name string) (out *Interface)

Interface returns the interface named name from this file, or nil if not found.

func (*File) Method

func (self *File) Method(name string) (out *Method)

Method returns the method named name from this file, or nil if not found.

func (*File) Struct

func (self *File) Struct(name string) (out *Struct)

Struct returns the struct named name from this file, or nil if not found.

func (*File) Type

func (self *File) Type(name string) (out *Type)

Type returns the type named name from this file, or nil if not found.

func (*File) Var

func (self *File) Var(name string) (out *Var)

Var returns the variable named name from this file, or nil if not found.

type FileMap

type FileMap = maps.OrderedMap[string, *File]

FileMap is an ordered map of files keyed by their filename in parse order.

type Func

type Func struct {
	Model
	// TypeParams are the function's type parameters.
	TypeParams *FieldMap
	// Params are the function's parameters.
	Params *FieldMap
	// Results are the function's return values.
	Results *FieldMap
}

Func represents a top-level function declaration.

func NewFunc

func NewFunc(file *File, name string) *Func

NewFunc creates a new Func for the given file and name.

type ImportSpec

type ImportSpec struct {
	// Doc is the import doc comment.
	Doc []string
	// Name is the import name, possibly empty, "." or some custom name.
	Name string
	// Path is the import path.
	Path string
}

ImportSpec represents an import specification for a package.

func NewImport

func NewImport(name, path string) *ImportSpec

NewImport creates a new ImportSpec with the given name and path.

func (*ImportSpec) Base

func (self *ImportSpec) Base() string

Base returns the base name of the imported package path.

type ImportSpecMap

type ImportSpecMap = maps.OrderedMap[string, *ImportSpec]

ImportSpecMap is an ordered map of import specs keyed by their path in parse order.

type Interface

type Interface struct {
	Model
	// Methods are the methods declared by this interface.
	Methods *MethodMap
	// Interfaces are the embedded interfaces.
	//
	// Keyed by the embedded interface type name.
	Interfaces *InterfaceMap
	// TypeParams are the interface's type parameters.
	TypeParams *FieldMap
}

Interface represents a top-level interface type declaration.

func NewInterface

func NewInterface(file *File, name string) *Interface

NewInterface creates a new Interface for the given file and name.

type InterfaceMap

type InterfaceMap = maps.OrderedMap[string, *Interface]

InterfaceMap is an ordered map of interfaces keyed by name in parse order.

type Method

type Method struct {
	Func
	// Receiver is the method's receiver, or nil for interface methods.
	Receiver *Field
}

Method represents a top-level method declaration.

func NewMethod

func NewMethod(file *File, name string) *Method

NewMethod creates a new Method for the given file and name.

type MethodMap

type MethodMap = maps.OrderedMap[string, *Method]

MethodMap is an ordered map of methods keyed by name in parse order.

type Model

type Model struct {

	// Doc is the declaration doc comment.
	Doc []string

	// Name is the declaration name.
	//
	// For [Struct], this will be the bare name of the struct type without type
	// parameters. Type parameters are stored separately in a [Struct]
	// definition.
	//
	// If struct field is unnamed Name will be equal to Type.
	// [Field.Unnamed] will be set to true as well.
	Name string
	// contains filtered or unexported fields
}

Model is the base struct embedded by all declarations.

It provides common fields like documentation and name, and implements the Declaration interface.

func (*Model) GetFile

func (self *Model) GetFile() *File

GetFile returns the parent file of the declaration.

func (*Model) GetPackage

func (self *Model) GetPackage() *Package

GetPackage returns the parent package of the declaration.

func (*Model) ImportSpecBySelectorExpr

func (self *Model) ImportSpecBySelectorExpr(selectorExpr string) *ImportSpec

ImportSpecBySelectorExpr returns the ImportSpec for the package from which the type qualified by selectorExpr (e.g., "pkg.TypeName") is imported.

It returns nil if not found or selectorExpr is invalid.

func (*Model) ResolveBasicType

func (self *Model) ResolveBasicType(typeName string) string

ResolveBasicType resolves the underlying basic type name for the given typeName by searching the type hierarchy of the parsed packages.

If typeName is already a basic type name, it returns typeName as is. If no basic type is found, it returns an empty string.

This method requires Config.TypeChecking to be enabled.

type Package

type Package struct {
	// Name is the package name, without path, as it appears in source code.
	Name string
	// Path is the package import path as used by go compiler.
	Path string
	// Files maps definitions of parsed go files by their full path.
	Files *FileMap
	// contains filtered or unexported fields
}

Package represents a parsed Go package.

It contains the package name, import path, files, and top-level declarations.

func NewPackage

func NewPackage(name, path string, pkg *packages.Package) *Package

NewPackage creates a new Package with the given name, path, and underlying packages.Package.

func (*Package) Const

func (self *Package) Const(name string) (out *Const)

Const returns the constant named name from this package, or nil if not found.

func (*Package) DeclFile

func (self *Package) DeclFile(typeName string) string

DeclFile returns the full filename of the file containing the declaration named typeName in this package. It returns an empty string if not found.

func (*Package) Func

func (self *Package) Func(name string) (out *Func)

Func returns the function named name from this package, or nil if not found.

func (*Package) HasDecl

func (self *Package) HasDecl(typeName string) bool

HasDecl returns true if a declaration named typeName exists in this package.

func (*Package) Interface

func (self *Package) Interface(name string) (out *Interface)

Interface returns the interface named name from this package, or nil if not found.

func (*Package) Method

func (self *Package) Method(name string) (out *Method)

Method returns the method named name from this package, or nil if not found.

func (*Package) Struct

func (self *Package) Struct(name string) (out *Struct)

Struct returns the struct named name from this package, or nil if not found.

func (*Package) Type

func (self *Package) Type(name string) (out *Type)

Type returns the type named name from this package, or nil if not found.

func (*Package) Var

func (self *Package) Var(name string) (out *Var)

Var returns the variable named name from this package, or nil if not found.

type PackageMap

type PackageMap = maps.OrderedMap[string, *Package]

PackageMap is an ordered map of packages keyed by their import path.

type Parser

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

Parser transforms loaded go/packages into the bast model.

func NewParser

func NewParser(config *Config) *Parser

NewParser creates a new Parser with the given config.

func (*Parser) Parse

func (self *Parser) Parse(pkgs []*packages.Package) (*Bast, error)

Parse parses the given loaded packages into a Bast.

It returns an error if parsing fails or if TypeCheckingErrors is true and any package has errors.

type Printer

type Printer struct {
	// PrintDoc, if true, includes documentation comments.
	PrintDoc bool
	// PrintComments, if true, includes non-doc comments.
	PrintComments bool
	// PrintConsts, if true, includes constants.
	PrintConsts bool
	// PrintVars, if true, includes variables.
	PrintVars bool
	// PrintTypes, if true, includes type declarations.
	PrintTypes bool
	// PrintFuncs, if true, includes functions.
	PrintFuncs bool
	// PrintMethods, if true, includes methods.
	PrintMethods bool
	// PrintStructs, if true, includes structs.
	PrintStructs bool
	// PrintInterfaces, if true, includes interfaces.
	PrintInterfaces bool
	// Indentation is the string used for indenting output (default "\t").
	Indentation string
}

Printer configures the formatting options for printing a Bast model.

func DefaultPrinter

func DefaultPrinter() *Printer

DefaultPrinter returns a Printer with all printing options enabled and tab indentation.

func (*Printer) Print

func (self *Printer) Print(w io.Writer, bast *Bast)

Print writes the Bast model to w using tabwriter for alignment.

type Struct

type Struct struct {
	Model
	// Fields are the struct's fields.
	Fields *FieldMap
	// TypeParams are the struct's type parameters.
	TypeParams *FieldMap
}

Struct represents a top-level struct type declaration.

func NewStruct

func NewStruct(file *File, name string) *Struct

NewStruct creates a new Struct for the given file and name.

func (*Struct) Methods

func (self *Struct) Methods() (out []*Method)

Methods returns the methods defined on this struct.

type Type

type Type struct {
	Model
	// Type is the underlying type of this type declaration.
	//
	// This may be a qualified selector like "pkg.Type".
	Type string
	// IsAlias is true if this is a type alias (using := instead of =).
	IsAlias bool
	// TypeParams are the type's type parameters.
	TypeParams *FieldMap
}

Type represents a top-level type declaration (not struct or interface).

func NewType

func NewType(file *File, name, typ string) *Type

NewType creates a new Type for the given file, name, and underlying type.

type Var

type Var struct {
	Model
	// Type is the variable's type, empty if inferred.
	Type string
	// Value is the variable's initial value, empty if not specified.
	Value string
}

Var represents a top-level variable declaration.

func NewVar

func NewVar(file *File, name, typ string) *Var

NewVar creates a new Var for the given file, name, and type.

Jump to

Keyboard shortcuts

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