Files

139 lines
2.4 KiB
Go
Raw Permalink Normal View History

2016-02-28 03:16:29 +03:00
package parser
import (
"go/ast"
"go/parser"
"go/token"
2019-04-02 14:32:02 +01:00
"os"
2016-02-28 03:16:29 +03:00
"strings"
)
const (
structComment = "easyjson:json"
structSkipComment = "easyjson:skip"
)
2016-02-28 03:16:29 +03:00
type Parser struct {
PkgPath string
PkgName string
StructNames []string
AllStructs bool
}
type visitor struct {
*Parser
2019-03-28 15:30:05 +01:00
name string
2016-02-28 03:16:29 +03:00
}
2020-08-12 14:22:55 +03:00
func (p *Parser) needType(comments *ast.CommentGroup) (skip, explicit bool) {
if comments == nil {
return
}
for _, v := range comments.List {
comment := v.Text
if len(comment) > 2 {
switch comment[1] {
case '/':
// -style comment (no newline at the end)
comment = comment[2:]
case '*':
/*-style comment */
comment = comment[2 : len(comment)-2]
}
}
2020-08-12 14:42:29 +03:00
for _, comment := range strings.Split(comment, "\n") {
comment = strings.TrimSpace(comment)
2020-08-12 14:22:55 +03:00
2020-08-12 14:42:29 +03:00
if strings.HasPrefix(comment, structSkipComment) {
return true, false
}
if strings.HasPrefix(comment, structComment) {
return false, true
}
2016-02-28 03:16:29 +03:00
}
}
2020-08-12 14:22:55 +03:00
return
2016-02-28 03:16:29 +03:00
}
func (v *visitor) Visit(n ast.Node) (w ast.Visitor) {
switch n := n.(type) {
2016-10-18 17:56:52 +07:00
case *ast.Package:
return v
2016-02-28 03:16:29 +03:00
case *ast.File:
v.PkgName = n.Name.String()
return v
case *ast.GenDecl:
2020-08-12 14:22:55 +03:00
skip, explicit := v.needType(n.Doc)
2019-03-28 15:30:05 +01:00
2020-05-10 14:08:06 +03:00
if skip || explicit {
for _, nc := range n.Specs {
switch nct := nc.(type) {
case *ast.TypeSpec:
nct.Doc = n.Doc
}
2019-03-28 15:30:05 +01:00
}
}
2016-02-28 03:16:29 +03:00
return v
case *ast.TypeSpec:
2020-08-12 14:22:55 +03:00
skip, explicit := v.needType(n.Doc)
2020-05-10 14:08:06 +03:00
if skip {
return nil
}
2019-03-28 15:30:05 +01:00
if !explicit && !v.AllStructs {
return nil
}
2016-02-28 03:16:29 +03:00
v.name = n.Name.String()
// Allow to specify non-structs explicitly independent of '-all' flag.
2019-03-28 15:30:05 +01:00
if explicit {
v.StructNames = append(v.StructNames, v.name)
return nil
}
2019-03-28 15:30:05 +01:00
2016-02-28 03:16:29 +03:00
return v
case *ast.StructType:
v.StructNames = append(v.StructNames, v.name)
return nil
}
return nil
}
2016-10-18 17:56:52 +07:00
func (p *Parser) Parse(fname string, isDir bool) error {
2016-02-28 03:16:29 +03:00
var err error
2016-10-18 17:56:52 +07:00
if p.PkgPath, err = getPkgPath(fname, isDir); err != nil {
2016-02-28 03:16:29 +03:00
return err
}
fset := token.NewFileSet()
2016-10-18 17:56:52 +07:00
if isDir {
2019-04-02 14:32:02 +01:00
packages, err := parser.ParseDir(fset, fname, excludeTestFiles, parser.ParseComments)
2016-10-18 17:56:52 +07:00
if err != nil {
return err
}
2016-02-28 03:16:29 +03:00
2016-10-18 17:56:52 +07:00
for _, pckg := range packages {
ast.Walk(&visitor{Parser: p}, pckg)
}
} else {
f, err := parser.ParseFile(fset, fname, nil, parser.ParseComments)
if err != nil {
return err
}
ast.Walk(&visitor{Parser: p}, f)
}
2016-02-28 03:16:29 +03:00
return nil
}
2017-07-28 15:13:56 -05:00
2019-04-02 14:32:02 +01:00
func excludeTestFiles(fi os.FileInfo) bool {
return !strings.HasSuffix(fi.Name(), "_test.go")
}