packager

package module
v0.0.7 Latest Latest
Warning

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

Go to latest
Published: Mar 9, 2024 License: MIT Imports: 14 Imported by: 1

README

Packager

It is just a wrapper over golang.org/x/tools/go/packages but contains all dependent packages with types info.

Packager provides access to random ast generic declaration by its pkg path and type name. It usefull when you want to work with go/types abstractions with access to *ast.GenDecl to get Doc and Comments of the Type/Field/etc.

Also you can convert your ast.Expr to types.Type back.

Example

package main

import (
	"fmt"
	"go/ast"

	"gitlab.com/so_literate/gentools/packager"

	"golang.org/x/tools/go/packages"
)

func main() {
	// Create your config of the x/tools/go/packages parser.
	pkgsConfig := packages.Config{
		// I want to get types and pkg info of the dir in my project.
		Mode: packages.NeedName | packages.NeedTypes | packages.NeedTypesInfo,
		Dir:  "./testdata/models",
	}

	pkgr, err := packager.New()
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	pkgs, err := pkgr.PackagesLoad(&pkgsConfig)
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	fmt.Println("Number of packages:", len(pkgs))

	// Just work with your parsed package using "go/types" abstactions:
	someType := pkgs[0].Types.Scope().Lookup("SomeType")
	fmt.Println("someType:", someType.Pkg().Path(), someType.Name())

	// If you need you can get *ast.GenDecl of any type from any package.
	// *ast.GenDecl contains docs and every comments of the type.
	astGen := pkgr.GetGenDeclOfType(someType.Pkg().Path(), someType.Name())
	fmt.Print("Top comments of the SomeType: ", astGen.Doc.Text())

	someTypeBackConverted := pkgr.GetTypeOfExpr(astGen.Specs[0].(*ast.TypeSpec).Type)

	// someTypeBackConverted is the same Underlying type of the Named "SomeType" struct.
	fmt.Println(someTypeBackConverted.String() == someType.Type().Underlying().String())
}

Documentation

Overview

Package packager contains some helpers to parse source code using golang.org/x/tools/go/packages. The package provides method to find Ast Generic Declaration of the object from "go/types" and method to find "go/types" declaration using Ast Expression.

Example
package main

import (
	"fmt"
	"go/ast"

	"gitlab.com/so_literate/gentools/packager"

	"golang.org/x/tools/go/packages"
)

func main() {
	// Create your config of the x/tools/go/packages parser.
	pkgsConfig := packages.Config{
		// I want to get types and pkg info of the dir in my project.
		Mode: packages.NeedName | packages.NeedTypes | packages.NeedTypesInfo,
		Dir:  "./testdata/models",
	}

	pkgr, err := packager.New()
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	pkgs, err := pkgr.PackagesLoad(&pkgsConfig)
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	fmt.Println("Number of packages:", len(pkgs))

	// Just work with your parsed package using "go/types" abstactions:
	someType := pkgs[0].Types.Scope().Lookup("SomeType")
	fmt.Println("someType:", someType.Pkg().Path(), someType.Name())

	// If you need you can get *ast.GenDecl of any type from any package.
	// *ast.GenDecl contains docs and every comments of the type.
	astGen := pkgr.GetGenDeclOfType(someType.Pkg().Path(), someType.Name())
	fmt.Print("Top comments of the SomeType: ", astGen.Doc.Text())

	someTypeBackConverted := pkgr.GetTypeOfExpr(astGen.Specs[0].(*ast.TypeSpec).Type)

	// someTypeBackConverted is the same Underlying type of the Named "SomeType" struct.
	fmt.Println(someTypeBackConverted.String() == someType.Type().Underlying().String())

}
Output:

Number of packages: 1
someType: gitlab.com/so_literate/gentools/packager/testdata/models SomeType
Top comments of the SomeType: SomeType doc of the type.
true

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrWrongPackagesAmount = errors.New("wrong amount of parsed packages")

ErrWrongPackagesAmount returns when packages parser returned unexpected amount of parsed packages.

Functions

func DefaultParserParseFile

func DefaultParserParseFile(fset *token.FileSet, filename string, src []byte) (*ast.File, error)

DefaultParserParseFile default go/packages func to parse files.

Types

type ConstValue added in v0.0.2

type ConstValue struct {
	Type *types.Const   // go/types representation of the value, contains type description.
	Spec *ast.ValueSpec // go/ast representation of the value, contains comments.
	// contains filtered or unexported fields
}

ConstValue constant value of the type.

type Packager

type Packager struct {

	// Patterns to skip for parsing, GOCACHE dir by default.
	SkipPatterns []*regexp.Regexp
	// Parsed ast files grouped by package path.
	AstByPackage map[string][]*ast.File
	// List of the parsed packages with access by path.
	Pkgs map[string]*packages.Package

	// Origin function from packages.Config.
	OriginParseFile func(fset *token.FileSet, filename string, src []byte) (*ast.File, error)
	// contains filtered or unexported fields
}

Packager contains all parsed ast files and all dependency package with access to fine any type or ast declaration.

func New

func New(igonrePackages ...string) (*Packager, error)

New creates new packager to parse go packages with access to every parsed ast file. It takes list of packages (regexp) to ignore in recursive scanning.

func (*Packager) FindConstValuesOfType added in v0.0.2

func (p *Packager) FindConstValuesOfType(namedType *types.Named) []*ConstValue

FindConstValuesOfType returns constant values of the named type. Useful if you want to find "Enum" values of the type.

Example
package main

import (
	"fmt"
	"go/types"

	"gitlab.com/so_literate/gentools/packager"

	"golang.org/x/tools/go/packages"
)

func main() {
	pkgsConfig := packages.Config{
		Mode: packages.NeedName | packages.NeedTypes | packages.NeedTypesInfo,
		Dir:  "./testdata/enum",
	}

	pkgr, err := packager.New()
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	pkgs, err := pkgr.PackagesLoad(&pkgsConfig)
	if err != nil {
		fmt.Println(err.Error())
		return
	}

	// just get your "enum" type.
	// Enum is a basic type with const values in the package.
	enum := pkgs[0].Types.Scope().Lookup("EnumInt").Type().(*types.Named)

	consts := pkgr.FindConstValuesOfType(enum)

	for _, value := range consts {
		fmt.Printf("%s: %s - %q\n", value.Type.Name(), value.Type.Val().String(), value.Spec.Comment.Text())
	}

}
Output:

EnumIntFirst: 1 - ""
EnumIntSecond: 2 - "Comment.\n"
EnumAlphaName: 3 - "Comment.\n"

func (*Packager) GetGenDeclOfType

func (p *Packager) GetGenDeclOfType(packagePath, scopeName string) *ast.GenDecl

GetGenDeclOfType looks for a generic declaration of the type. Takes full module path of the package and name of the type. For example you can find type declaration in the package:

GetGenDecl("path/to/package", "TypeName")

Returns nil if not found. ast.GenDecl contains Doc and Comments block of the type.

func (*Packager) GetTypeOfExpr

func (p *Packager) GetTypeOfExpr(expr ast.Expr) types.Type

GetTypeOfExpr looks for types.Type representation of the ast.Expr. For example you can get types description of the ast object.

methodType = GetTypeOfExpr((*ast.InterfaceType).Methods.List[0].Type) // methodType.(types.Type)

Returns nil if not found. types.Type contains more useful abstractions of the type.

func (*Packager) PackagesLoad

func (p *Packager) PackagesLoad(config *packages.Config, patterns ...string) ([]*packages.Package, error)

PackagesLoad looks like a packages.Load method with additional parsing of the each dependency package. Returns parsed packages using parser config. Field Pkgs contains all parsed packages and field AstByPackage contains all parsed ast.Files.

Jump to

Keyboard shortcuts

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