mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-02 03:01:45 +08:00
Support references to structs in other packages
This commit is contained in:
parent
8fd0e06c24
commit
cd11c0a83c
@ -6,6 +6,7 @@ import (
|
||||
"go/build"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
@ -29,6 +30,7 @@ type ParameterType struct {
|
||||
IsPointer bool
|
||||
MapKey *ParameterType
|
||||
MapValue *ParameterType
|
||||
Package string
|
||||
}
|
||||
|
||||
type Parameter struct {
|
||||
@ -59,6 +61,7 @@ type ParsedPackage struct {
|
||||
type Project struct {
|
||||
Path string
|
||||
BoundMethods map[packagePath]map[structName][]*BoundMethod
|
||||
Models map[packagePath]map[structName]*StructDef
|
||||
}
|
||||
|
||||
func ParseProject(projectPath string) (*Project, error) {
|
||||
@ -74,13 +77,19 @@ func ParseProject(projectPath string) (*Project, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, pkg := range packageCache {
|
||||
if len(pkg.StructCache) > 0 {
|
||||
if result.Models == nil {
|
||||
result.Models = make(map[packagePath]map[structName]*StructDef)
|
||||
}
|
||||
result.Models[pkg.Path] = pkg.StructCache
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (p *Project) parseDirectory(dir string) (map[string]*ParsedPackage, error) {
|
||||
println("Parsing directory " + dir)
|
||||
if packageCache[dir] != nil {
|
||||
println("Found directory in cache!")
|
||||
return map[string]*ParsedPackage{dir: packageCache[dir]}, nil
|
||||
}
|
||||
// Parse the directory
|
||||
@ -105,7 +114,7 @@ func (p *Project) parseDirectory(dir string) (map[string]*ParsedPackage, error)
|
||||
Dir: getDirectoryForPackage(pkg),
|
||||
StructCache: make(map[structName]*StructDef),
|
||||
}
|
||||
packageCache[dir] = parsedPackage
|
||||
packageCache[packageName] = parsedPackage
|
||||
result[packageName] = parsedPackage
|
||||
}
|
||||
return result, nil
|
||||
@ -115,9 +124,8 @@ func (p *Project) findApplicationNewCalls(pkgs map[string]*ParsedPackage) (err e
|
||||
|
||||
var callFound bool
|
||||
|
||||
for packageName, pkg := range pkgs {
|
||||
for _, pkg := range pkgs {
|
||||
thisPackage := pkg.Pkg
|
||||
println(" - Looking in package: " + packageName)
|
||||
// Iterate through the package's files
|
||||
for _, file := range thisPackage.Files {
|
||||
// Use an ast.Inspector to find the calls to application.New
|
||||
@ -338,12 +346,20 @@ func (p *Project) parseParameterType(field *ast.Field, pkg *ParsedPackage) *Para
|
||||
result := &ParameterType{}
|
||||
result.Name = getTypeString(field.Type)
|
||||
switch t := field.Type.(type) {
|
||||
case *ast.Ident:
|
||||
result.IsStruct = isStructType(t)
|
||||
case *ast.StarExpr:
|
||||
result = p.parseParameterType(&ast.Field{Type: t.X}, pkg)
|
||||
result.IsPointer = true
|
||||
result.IsStruct = isStructType(t.X)
|
||||
case *ast.StructType:
|
||||
result.IsStruct = true
|
||||
case *ast.SelectorExpr:
|
||||
extPackage, err := p.getParsedPackageFromName(t.X.(*ast.Ident).Name, pkg)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
result.IsStruct = p.getStructDef(t.Sel.Name, extPackage)
|
||||
result.Package = extPackage.Path
|
||||
case *ast.ArrayType:
|
||||
result.IsSlice = true
|
||||
result.IsStruct = isStructType(t.Elt)
|
||||
@ -355,18 +371,18 @@ func (p *Project) parseParameterType(field *ast.Field, pkg *ParsedPackage) *Para
|
||||
default:
|
||||
}
|
||||
if result.IsStruct {
|
||||
_, ok := pkg.StructCache[result.Name]
|
||||
if !ok {
|
||||
p.getStructDef(result.Name, pkg)
|
||||
p.getStructDef(result.Name, pkg)
|
||||
if result.Package == "" {
|
||||
result.Package = pkg.Path
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (p *Project) getStructDef(name string, pkg *ParsedPackage) {
|
||||
func (p *Project) getStructDef(name string, pkg *ParsedPackage) bool {
|
||||
_, ok := pkg.StructCache[name]
|
||||
if ok {
|
||||
return
|
||||
return true
|
||||
}
|
||||
// Iterate over all files in the package
|
||||
for _, file := range pkg.Pkg.Files {
|
||||
@ -386,6 +402,7 @@ func (p *Project) getStructDef(name string, pkg *ParsedPackage) {
|
||||
}
|
||||
pkg.StructCache[name] = result
|
||||
result.Fields = p.parseStructFields(structType, pkg)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -394,6 +411,7 @@ func (p *Project) getStructDef(name string, pkg *ParsedPackage) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *Project) parseStructFields(structType *ast.StructType, pkg *ParsedPackage) []*Field {
|
||||
@ -419,6 +437,9 @@ func (p *Project) parseStructFields(structType *ast.StructType, pkg *ParsedPacka
|
||||
if !ok {
|
||||
p.getStructDef(paramType.Name, pkg)
|
||||
}
|
||||
if paramType.Package == "" {
|
||||
paramType.Package = pkg.Path
|
||||
}
|
||||
}
|
||||
thisField.Type = paramType
|
||||
result = append(result, thisField)
|
||||
@ -445,13 +466,15 @@ func (p *Project) getParsedPackageFromName(packageName string, currentPackage *P
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &ParsedPackage{
|
||||
result := &ParsedPackage{
|
||||
Pkg: pkg,
|
||||
Name: packageName,
|
||||
Path: path,
|
||||
Dir: dir,
|
||||
StructCache: make(map[string]*StructDef),
|
||||
}, nil
|
||||
}
|
||||
packageCache[path] = result
|
||||
return result, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -490,6 +513,8 @@ func getTypeString(expr ast.Expr) string {
|
||||
return getTypeString(t.Elt)
|
||||
case *ast.MapType:
|
||||
return "map"
|
||||
case *ast.SelectorExpr:
|
||||
return getTypeString(t.Sel)
|
||||
default:
|
||||
return "any"
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ func TestParseDirectory(t *testing.T) {
|
||||
name string
|
||||
dir string
|
||||
wantBoundMethods map[string]map[string][]*BoundMethod
|
||||
wantModels map[string]map[string]*StructDef
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
@ -689,6 +690,7 @@ func TestParseDirectory(t *testing.T) {
|
||||
Name: "Person",
|
||||
IsPointer: true,
|
||||
IsStruct: true,
|
||||
Package: "main",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -709,6 +711,7 @@ func TestParseDirectory(t *testing.T) {
|
||||
Name: "Person",
|
||||
IsPointer: true,
|
||||
IsStruct: true,
|
||||
Package: "main",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -718,6 +721,7 @@ func TestParseDirectory(t *testing.T) {
|
||||
Name: "Person",
|
||||
IsPointer: true,
|
||||
IsStruct: true,
|
||||
Package: "main",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -841,6 +845,30 @@ func TestParseDirectory(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
wantModels: map[string]map[string]*StructDef{
|
||||
"main": {
|
||||
"Person": {
|
||||
Name: "Person",
|
||||
Fields: []*Field{
|
||||
{
|
||||
Name: "Name",
|
||||
Type: &ParameterType{
|
||||
Name: "string",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Parent",
|
||||
Type: &ParameterType{
|
||||
Name: "Person",
|
||||
IsStruct: true,
|
||||
IsPointer: true,
|
||||
Package: "main",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
@ -960,6 +988,7 @@ func TestParseDirectory(t *testing.T) {
|
||||
Name: "Person",
|
||||
IsPointer: true,
|
||||
IsStruct: true,
|
||||
Package: "main",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -973,8 +1002,10 @@ func TestParseDirectory(t *testing.T) {
|
||||
Outputs: []*Parameter{
|
||||
{
|
||||
Type: &ParameterType{
|
||||
Name: "int",
|
||||
IsSlice: true,
|
||||
Name: "Address",
|
||||
IsStruct: true,
|
||||
IsPointer: true,
|
||||
Package: "github.com/wailsapp/wails/v3/internal/parser/testdata/struct_literal_multiple_other/services",
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -982,6 +1013,55 @@ func TestParseDirectory(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
wantModels: map[string]map[string]*StructDef{
|
||||
"main": {
|
||||
"Person": {
|
||||
Name: "Person",
|
||||
Fields: []*Field{
|
||||
{
|
||||
Name: "Name",
|
||||
Type: &ParameterType{
|
||||
Name: "string",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Address",
|
||||
Type: &ParameterType{
|
||||
Name: "Address",
|
||||
IsStruct: true,
|
||||
IsPointer: true,
|
||||
Package: "github.com/wailsapp/wails/v3/internal/parser/testdata/struct_literal_multiple_other/services",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"github.com/wailsapp/wails/v3/internal/parser/testdata/struct_literal_multiple_other/services": {
|
||||
"Address": {
|
||||
Name: "Address",
|
||||
Fields: []*Field{
|
||||
{
|
||||
Name: "Street",
|
||||
Type: &ParameterType{
|
||||
Name: "string",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "State",
|
||||
Type: &ParameterType{
|
||||
Name: "string",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Country",
|
||||
Type: &ParameterType{
|
||||
Name: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@ -994,6 +1074,9 @@ func TestParseDirectory(t *testing.T) {
|
||||
if diff := cmp.Diff(tt.wantBoundMethods, got.BoundMethods); diff != "" {
|
||||
t.Errorf("ParseDirectory() failed:\n" + diff)
|
||||
}
|
||||
if diff := cmp.Diff(tt.wantModels, got.Models); diff != "" {
|
||||
t.Errorf("ParseDirectory() failed:\n" + diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -16,7 +16,8 @@ type GreetService struct {
|
||||
}
|
||||
|
||||
type Person struct {
|
||||
Name string
|
||||
Name string
|
||||
Address *services.Address
|
||||
}
|
||||
|
||||
// Greet does XYZ
|
||||
|
@ -6,7 +6,17 @@ type OtherService struct {
|
||||
t int
|
||||
}
|
||||
|
||||
// Yay does this and that
|
||||
func (o *OtherService) Yay() []int {
|
||||
return []int{0, 1, 2}
|
||||
type Address struct {
|
||||
Street string
|
||||
State string
|
||||
Country string
|
||||
}
|
||||
|
||||
// Yay does this and that
|
||||
func (o *OtherService) Yay() *Address {
|
||||
return &Address{
|
||||
Street: "123 Pitt Street",
|
||||
State: "New South Wales",
|
||||
Country: "Australia",
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user