Files
easyjson/parser/parser.go
T
warnar boekkooi fc8e2d7bfe Add support for TypeSpec docs
Since doc's can be added on both the generic declaration (GenDecl) as well as on the type declaration (TypeSpec) we need to check both.
In order to check both declaration we copy the GenDecl docs to the TypeSpec docs if the TypeSpec has no documentation.
2019-03-28 17:45:34 +01:00

111 lines
1.9 KiB
Go

package parser
import (
"bytes"
"go/ast"
"go/parser"
"go/token"
"os/exec"
"strings"
)
const structComment = "easyjson:json"
type Parser struct {
PkgPath string
PkgName string
StructNames []string
AllStructs bool
}
type visitor struct {
*Parser
name string
}
func (p *Parser) needType(comments string) bool {
for _, v := range strings.Split(comments, "\n") {
if strings.HasPrefix(v, structComment) {
return true
}
}
return false
}
func (v *visitor) Visit(n ast.Node) (w ast.Visitor) {
switch n := n.(type) {
case *ast.Package:
return v
case *ast.File:
v.PkgName = n.Name.String()
return v
case *ast.GenDecl:
explicit := v.needType(n.Doc.Text())
if !explicit {
return v
}
for _, nc := range n.Specs {
switch nct := nc.(type) {
case *ast.TypeSpec:
nct.Doc = n.Doc
}
}
return v
case *ast.TypeSpec:
explicit := v.needType(n.Doc.Text())
if !explicit && !v.AllStructs {
return nil
}
v.name = n.Name.String()
// Allow to specify non-structs explicitly independent of '-all' flag.
if explicit {
v.StructNames = append(v.StructNames, v.name)
return nil
}
return v
case *ast.StructType:
v.StructNames = append(v.StructNames, v.name)
return nil
}
return nil
}
func (p *Parser) Parse(fname string, isDir bool) error {
var err error
if p.PkgPath, err = getPkgPath(fname, isDir); err != nil {
return err
}
fset := token.NewFileSet()
if isDir {
packages, err := parser.ParseDir(fset, fname, nil, parser.ParseComments)
if err != nil {
return err
}
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)
}
return nil
}
func getDefaultGoPath() (string, error) {
output, err := exec.Command("go", "env", "GOPATH").Output()
return string(bytes.TrimSpace(output)), err
}