Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add input/output formats #149

Merged
merged 6 commits into from
Jun 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion builder/struct.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,11 +239,11 @@ func mapField(
OutputPackagePath: ctx.OutputPackagePath,
ErrorPrefix: "Error parsing struct method",
Params: method.ParamsNone,
CustomCall: nextIDCode,
})
if err != nil {
return nil, nil, nil, nil, false, NewError(err.Error()).Lift(lift...)
}
def.Call = nextIDCode

methodCallInner, callID, callErr := gen.CallMethod(ctx, def, nil, nil, def.Target, errPath)
if callErr != nil {
Expand Down
121 changes: 81 additions & 40 deletions comments/parse_docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
prefix = "goverter"
delimter = ":"
converterMarker = prefix + delimter + "converter"
variablesMarker = prefix + delimter + "variables"
)

// ParseDocsConfig provides input to the ParseDocs method below.
Expand All @@ -38,9 +39,8 @@
// ParseDocs parses the docs for the given pattern.
func ParseDocs(c ParseDocsConfig) ([]config.RawConverter, error) {
loadCfg := &packages.Config{
Mode: packages.NeedSyntax | packages.NeedCompiledGoFiles | packages.NeedTypes |
packages.NeedModule | packages.NeedFiles | packages.NeedName | packages.NeedImports,
Dir: c.WorkingDir,
Mode: packages.NeedName | packages.NeedTypes | packages.NeedTypesInfo | packages.NeedSyntax,
Dir: c.WorkingDir,
}
if c.BuildTags != "" {
loadCfg.BuildFlags = append(loadCfg.BuildFlags, "-tags", c.BuildTags)
Expand Down Expand Up @@ -75,77 +75,114 @@
return rawConverters, nil
}

func parseFunctions(fset *token.FileSet, pkg *types.Package, decl *ast.GenDecl, comments string) ([]config.RawConverter, error) {
if decl.Tok != token.VAR {
return nil, fmt.Errorf("%s must be defined on %q-block but was %q", converterMarker, token.VAR, decl.Tok.String())
}

location := fset.Position(decl.Pos())
converterLines := parseRawLines(fileWithLine(location), comments)

result := map[string]config.RawLines{}
for _, spec := range decl.Specs {
value, ok := spec.(*ast.ValueSpec)
if !ok {
return nil, fmt.Errorf("expected value spec but got %#v", spec)

Check warning on line 90 in comments/parse_docs.go

View check run for this annotation

Codecov / codecov/patch

comments/parse_docs.go#L90

Added line #L90 was not covered by tests
}
if len(value.Names) != 1 {
return nil, fmt.Errorf("must have one name")

Check warning on line 93 in comments/parse_docs.go

View check run for this annotation

Codecov / codecov/patch

comments/parse_docs.go#L93

Added line #L93 was not covered by tests
}
name := value.Names[0].Name

location := fileWithLine(fset.Position(value.Pos()))
result[name] = parseRawLines(location, value.Doc.Text())
}

converter := config.RawConverter{
FileName: location.Filename,
Converter: converterLines,
Methods: result,
PackageName: pkg.Name(),
PackagePath: pkg.Path(),
}
return []config.RawConverter{converter}, nil
}

func parseGenDecl(fset *token.FileSet, pkg *types.Package, decl *ast.GenDecl) ([]config.RawConverter, error) {
declDocs := decl.Doc.Text()

if strings.Contains(declDocs, variablesMarker) {
return parseFunctions(fset, pkg, decl, declDocs)
}

if strings.Contains(declDocs, converterMarker) {
if decl.Tok != token.TYPE {
return nil, fmt.Errorf("%s must be defined on %q-block but was %q", converterMarker, token.TYPE, decl.Tok.String())
}

if len(decl.Specs) != 1 {
return nil, fmt.Errorf("found %s on type but it has multiple interfaces inside", converterMarker)
}
typeSpec, ok := decl.Specs[0].(*ast.TypeSpec)
if !ok {
return nil, fmt.Errorf("%s may only be applied to type declarations ", converterMarker)
}
interfaceType, ok := typeSpec.Type.(*ast.InterfaceType)
if !ok {
return nil, fmt.Errorf("%s may only be applied to type interface declarations ", converterMarker)
}
typeName := typeSpec.Name.String()

location := fset.Position(decl.Pos())
converterLines := parseRawLines(location.String(), declDocs)
methods, err := parseInterface(fset, interfaceType)
c, err := parseInterface(fset, pkg, typeSpec, declDocs)
if err != nil {
return nil, fmt.Errorf("type %s: %s", typeName, err)
}
converter := config.RawConverter{
FileSource: location.Filename,
InterfaceName: typeName,
Converter: converterLines,
Methods: methods,
Package: pkg.Path(),
return nil, err
}
return []config.RawConverter{converter}, nil
return []config.RawConverter{c}, nil
}

var converters []config.RawConverter

for _, spec := range decl.Specs {
if typeSpec, ok := spec.(*ast.TypeSpec); ok && strings.Contains(typeSpec.Doc.Text(), converterMarker) {
interfaceType, ok := typeSpec.Type.(*ast.InterfaceType)
if !ok {
return nil, fmt.Errorf("%s may only be applied to type interface declarations ", converterMarker)
}
typeName := typeSpec.Name.String()
location := fset.Position(interfaceType.Pos())
lines := parseRawLines(location.String(), typeSpec.Doc.Text())
methods, err := parseInterface(fset, interfaceType)
c, err := parseInterface(fset, pkg, typeSpec, typeSpec.Doc.Text())
if err != nil {
return nil, fmt.Errorf("type %s: %s", typeName, err)
return nil, err
}
converters = append(converters, config.RawConverter{
FileSource: location.Filename,
InterfaceName: typeName,
Converter: lines,
Methods: methods,
Package: pkg.Path(),
})
converters = append(converters, c)
}
}

return converters, nil
}

func parseInterface(location *token.FileSet, inter *ast.InterfaceType) (map[string]config.RawLines, error) {
func parseInterface(fset *token.FileSet, pkg *types.Package, typeSpec *ast.TypeSpec, declDocs string) (config.RawConverter, error) {
astInterface, ok := typeSpec.Type.(*ast.InterfaceType)
if !ok {
return config.RawConverter{}, fmt.Errorf("%s may only be applied to type interface declarations ", converterMarker)
}
typeName := typeSpec.Name.String()

location := fset.Position(typeSpec.Pos())
converterLines := parseRawLines(fileWithLine(location), declDocs)
methods, err := parseInterfaceMethods(fset, astInterface)
if err != nil {
return config.RawConverter{}, fmt.Errorf("type %s: %s", typeName, err)

Check warning on line 163 in comments/parse_docs.go

View check run for this annotation

Codecov / codecov/patch

comments/parse_docs.go#L163

Added line #L163 was not covered by tests
}
converter := config.RawConverter{
InterfaceName: typeName,
FileName: location.Filename,
Converter: converterLines,
Methods: methods,
PackageName: pkg.Name(),
PackagePath: pkg.Path(),
}
return converter, nil
}

func parseInterfaceMethods(location *token.FileSet, inter *ast.InterfaceType) (map[string]config.RawLines, error) {
result := map[string]config.RawLines{}
for _, method := range inter.Methods.List {
if len(method.Names) != 1 {
return result, fmt.Errorf("method must have one name")
}
name := method.Names[0].String()

location := location.Position(method.Pos()).String()
result[name] = parseRawLines(location, method.Doc.Text())
location := location.Position(method.Pos())
result[name] = parseRawLines(fileWithLine(location), method.Doc.Text())
}
return result, nil
}
Expand All @@ -162,3 +199,7 @@
}
return raw
}

func fileWithLine(p token.Position) string {
return fmt.Sprintf("%s:%d", p.Filename, p.Line)
}
12 changes: 4 additions & 8 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ type RawLines struct {
}

type RawConverter struct {
Package string
PackagePath string
PackageName string
InterfaceName string
Converter RawLines
Methods map[string]RawLines
FileSource string
FileName string
}

type Raw struct {
Expand Down Expand Up @@ -46,14 +47,9 @@ func Parse(raw *Raw) ([]*Converter, error) {

ctx := &context{Loader: loader, EnumTransformers: raw.EnumTransformers}

global, err := parseGlobal(ctx, raw.Global)
if err != nil {
return nil, err
}

converters := []*Converter{}
for _, rawConverter := range raw.Converters {
converter, err := parseConverter(ctx, &rawConverter, *global)
converter, err := parseConverter(ctx, &rawConverter, raw.Global)
if err != nil {
return nil, err
}
Expand Down
Loading
Loading