github.com/kazu/loncha@v0.6.3/structer/structer.go (about)

     1  package structer
     2  
     3  import (
     4  	"fmt"
     5  	"go/ast"
     6  	"go/importer"
     7  	"go/parser"
     8  	"go/token"
     9  	"go/types"
    10  	"io"
    11  	"io/ioutil"
    12  	"path"
    13  	"path/filepath"
    14  	"strings"
    15  
    16  	"github.com/pkg/errors"
    17  
    18  	"text/template"
    19  
    20  	"github.com/davecgh/go-spew/spew"
    21  	"go.uber.org/zap"
    22  )
    23  
    24  type StructInfo struct {
    25  	PkgName  string
    26  	Name     string
    27  	Fields   []FieldInfo
    28  	Embedded []string
    29  }
    30  
    31  type FieldInfo struct {
    32  	Name string
    33  	Type string
    34  }
    35  
    36  var Logger *zap.Logger
    37  
    38  func SetupLogger() {
    39  	Logger, _ = zap.NewProduction()
    40  }
    41  
    42  func LoadAstf(dir string, fset *token.FileSet) (astfs []*ast.File, err error) {
    43  
    44  	files, err := filepath.Glob(filepath.Join(dir, "*"))
    45  	if err != nil {
    46  		return
    47  	}
    48  
    49  	for _, file := range files {
    50  		if filepath.Ext(file) != ".go" {
    51  			continue
    52  		}
    53  		if match, _ := filepath.Match("*_test.go", filepath.Base(file)); match {
    54  			continue
    55  		}
    56  
    57  		astf, err := parser.ParseFile(fset, file, LoadFile(file), 0)
    58  		if err != nil {
    59  			return nil, err
    60  		}
    61  		astfs = append(astfs, astf)
    62  	}
    63  	return
    64  }
    65  
    66  func StrcutInfos(src string, pkgname string) (infos []StructInfo, err error) {
    67  
    68  	SetupLogger()
    69  
    70  	fset := token.NewFileSet()
    71  
    72  	//astf, _ := parser.ParseFile(fset, src, LoadFile(src), 0)
    73  	astfs, err := LoadAstf(path.Dir(src), fset)
    74  	if err != nil {
    75  		err = errors.Wrap(err, "parse fail")
    76  		return
    77  	}
    78  
    79  	conf := types.Config{Importer: importer.For("source", nil), DisableUnusedImportCheck: true}
    80  	pkg, err := conf.Check(pkgname, fset, astfs, nil)
    81  	_ = pkg
    82  	if err != nil {
    83  		err = errors.Wrap(err, fmt.Sprintf("fail check\n\tastfs=%+v\n\tfset=%+v\n\tpkg=%s\n\n", astfs, fset, spew.Sdump(pkg)))
    84  		return
    85  	}
    86  
    87  	Logger.Debug("Package info",
    88  		zap.String("Package", pkg.Path()),
    89  		zap.String("Name", pkg.Name()),
    90  		zap.Reflect("Imports", pkg.Imports()),
    91  		zap.Strings("Scope.Names", pkg.Scope().Names()),
    92  		zap.String("Scope", pkg.Scope().String()))
    93  
    94  	scope := pkg.Scope()
    95  
    96  	for _, name := range scope.Names() {
    97  		obj := scope.Lookup(name)
    98  		_ = obj
    99  
   100  		internal, found_struct := obj.Type().Underlying().(*types.Struct)
   101  		if !found_struct {
   102  			continue
   103  		}
   104  		sinfo := StructInfo{
   105  			PkgName: pkgname,
   106  			Name:    obj.Name(),
   107  			//Fields:  map[string]string{},
   108  		}
   109  		for i := 0; i < internal.NumFields(); i++ {
   110  			f := internal.Field(i)
   111  			if !f.IsField() {
   112  				continue
   113  			}
   114  			if f.Embedded() {
   115  				sinfo.Embedded = append(sinfo.Embedded, f.Name())
   116  			} else {
   117  				//sinfo.Fields[f.Name()] = f.Type().String()
   118  				sinfo.Fields = append(sinfo.Fields, FieldInfo{Name: f.Name(), Type: f.Type().String()})
   119  			}
   120  		}
   121  		Logger.Debug("Object",
   122  			zap.String("Object", spew.Sdump(obj)),
   123  			zap.String("Type", spew.Sdump(obj.Type())),
   124  			zap.String("Field:   %s\n", spew.Sdump(sinfo.Fields)))
   125  		infos = append(infos, sinfo)
   126  	}
   127  	return
   128  }
   129  
   130  func LoadFile(src string) string {
   131  	data, _ := ioutil.ReadFile(src)
   132  	return string(data)
   133  }
   134  
   135  func Dump(s io.Writer, fset *token.FileSet, d ast.Decl) {
   136  	ast.Fprint(s, fset, d, ast.NotNilFilter)
   137  	fmt.Fprint(s, "\n")
   138  
   139  }
   140  
   141  func (info StructInfo) FromTemplate(path string) (out string, err error) {
   142  	tmpStr := LoadFile(path)
   143  
   144  	t := template.Must(template.New("info").Parse(tmpStr))
   145  	s := &strings.Builder{}
   146  	err = t.Execute(s, info)
   147  	out = s.String()
   148  	return
   149  }