Reworked project parser *working*

This commit is contained in:
Lea Anthony
2020-11-07 07:03:04 +11:00
parent 58f96c9da8
commit 6863a5bf58
15 changed files with 1078 additions and 0 deletions

View File

@@ -0,0 +1,55 @@
package parser
import (
"go/ast"
"golang.org/x/tools/go/packages"
)
func (p *Parser) getApplicationVariableName(pkg *packages.Package, wailsImportName string) (string, bool) {
var applicationVariableName = ""
// Iterate through the whole package looking for the application name
for _, fileAst := range pkg.Syntax {
ast.Inspect(fileAst, func(n ast.Node) bool {
// Parse Assignments looking for application name
if assignStmt, ok := n.(*ast.AssignStmt); ok {
// Check the RHS is of the form:
// `app := wails.CreateApp()` or
// `app := wails.CreateAppWithOptions`
for _, rhs := range assignStmt.Rhs {
ce, ok := rhs.(*ast.CallExpr)
if !ok {
continue
}
se, ok := ce.Fun.(*ast.SelectorExpr)
if !ok {
continue
}
i, ok := se.X.(*ast.Ident)
if !ok {
continue
}
// Have we found the wails import name?
if i.Name == wailsImportName {
// Check we are calling a function to create the app
if se.Sel.Name == "CreateApp" || se.Sel.Name == "CreateAppWithOptions" {
if len(assignStmt.Lhs) == 1 {
i, ok := assignStmt.Lhs[0].(*ast.Ident)
if ok {
// Found the app variable name
applicationVariableName = i.Name
return false
}
}
}
}
}
}
return true
})
}
return applicationVariableName, applicationVariableName != ""
}

View File

@@ -0,0 +1,155 @@
package parser
import (
"go/ast"
"golang.org/x/tools/go/packages"
)
func (p *Parser) getImportByName(pkg *packages.Package, importName string) *packages.Package {
// Find package path
for _, imp := range pkg.Imports {
if imp.Name == importName {
return imp
}
}
return nil
}
func (p *Parser) findBoundStructsInPackage(pkg *packages.Package, applicationVariableName string) []*StructReference {
var boundStructs []*StructReference
// Iterate through the whole package looking for the bound structs
for _, fileAst := range pkg.Syntax {
ast.Inspect(fileAst, func(n ast.Node) bool {
// Parse Call expressions looking for bind calls
callExpr, ok := n.(*ast.CallExpr)
if !ok {
return true
}
// Check this is the right kind of expression (something.something())
f, ok := callExpr.Fun.(*ast.SelectorExpr)
if !ok {
return true
}
ident, ok := f.X.(*ast.Ident)
if !ok {
return true
}
if ident.Name != applicationVariableName {
return true
}
if f.Sel.Name != "Bind" {
return true
}
if len(callExpr.Args) != 1 {
return true
}
// Work out what was bound
switch boundItem := callExpr.Args[0].(type) {
// // app.Bind( someFunction() )
// case *ast.CallExpr:
// switch fn := boundItem.Fun.(type) {
// case *ast.Ident:
// boundStructs = append(boundStructs, newStruct(pkg.Name, fn.Name))
// println("Found bound function:", fn.Name)
// case *ast.SelectorExpr:
// ident, ok := fn.X.(*ast.Ident)
// if !ok {
// return true
// }
// packageName := ident.Name
// functionName := fn.Sel.Name
// println("Found bound function:", packageName+"."+functionName)
// strct := p.getFunctionReturnType(packageName, functionName)
// if strct == nil {
// // Unable to resolve function
// return true
// }
// boundStructs = append(boundStructs, strct)
// }
// Binding struct pointer literals
case *ast.UnaryExpr:
if boundItem.Op.String() != "&" {
return true
}
cl, ok := boundItem.X.(*ast.CompositeLit)
if !ok {
return true
}
switch boundStructExp := cl.Type.(type) {
// app.Bind( &myStruct{} )
case *ast.Ident:
boundStruct := newStructReference(pkg.Name, boundStructExp.Name)
boundStructs = append(boundStructs, boundStruct)
// app.Bind( &mypackage.myStruct{} )
case *ast.SelectorExpr:
var structName = ""
var packageName = ""
switch x := boundStructExp.X.(type) {
case *ast.Ident:
packageName = x.Name
default:
// TODO: Save these warnings
// println("Identifier in binding not supported:")
return true
}
structName = boundStructExp.Sel.Name
referencedPackage := p.getImportByName(pkg, packageName)
boundStruct := newStructReference(referencedPackage.Name, structName)
boundStructs = append(boundStructs, boundStruct)
}
// Binding struct literals
case *ast.CompositeLit:
switch literal := boundItem.Type.(type) {
// app.Bind( myStruct{} )
case *ast.Ident:
structName := literal.Name
boundStruct := newStructReference(pkg.Name, structName)
boundStructs = append(boundStructs, boundStruct)
// app.Bind( mypackage.myStruct{} )
case *ast.SelectorExpr:
var structName = ""
var packageName = ""
switch x := literal.X.(type) {
case *ast.Ident:
packageName = x.Name
default:
// TODO: Save these warnings
// println("Identifier in binding not supported:")
return true
}
structName = literal.Sel.Name
referencedPackage := p.getImportByName(pkg, packageName)
boundStruct := newStructReference(referencedPackage.Name, structName)
boundStructs = append(boundStructs, boundStruct)
}
default:
// TODO: Save these warnings
// println("Unsupported bind expression:")
// spew.Dump(boundItem)
}
return true
})
}
return boundStructs
}

21
v2/pkg/parser/comments.go Normal file
View File

@@ -0,0 +1,21 @@
package parser
import (
"go/ast"
"strings"
)
func (p *Parser) parseComments(comments *ast.CommentGroup) []string {
var result []string
if comments == nil {
return result
}
for _, comment := range comments.List {
commentText := strings.TrimPrefix(comment.Text, "//")
result = append(result, commentText)
}
return result
}

112
v2/pkg/parser/field.go Normal file
View File

@@ -0,0 +1,112 @@
package parser
import (
"fmt"
"go/ast"
)
// Field defines a parsed struct field
type Field struct {
Name string
Type string
Struct *Struct
Comments []string
// This struct reference is to temporarily hold the name
// of the struct during parsing
structReference *StructReference
}
func (p *Parser) parseField(field *ast.Field, thisPackageName string) ([]*Field, error) {
var result []*Field
var fieldType string
var structReference *StructReference
// Determine type
switch t := field.Type.(type) {
case *ast.Ident:
fieldType = t.Name
case *ast.StarExpr:
fieldType = "struct"
packageName, structName, err := p.parseStructNameFromStarExpr(t)
if err != nil {
return nil, err
}
// If we don't ahve a package name, it means it's in this package
if packageName == "" {
packageName = thisPackageName
}
// Temporarily store the struct reference
structReference = newStructReference(packageName, structName)
default:
return nil, fmt.Errorf("Unsupported field found in struct: %+v", t)
}
// Loop over names if we have
if len(field.Names) > 0 {
for _, name := range field.Names {
// Create a field per name
thisField := &Field{
Comments: p.parseComments(field.Doc),
}
thisField.Name = name.Name
thisField.Type = fieldType
thisField.structReference = structReference
result = append(result, thisField)
}
return result, nil
}
// When we have no name
thisField := &Field{
Comments: p.parseComments(field.Doc),
}
thisField.Type = fieldType
thisField.structReference = structReference
result = append(result, thisField)
return result, nil
}
func (p *Parser) resolveFieldReferences(fields []*Field) error {
// Loop over fields
for _, field := range fields {
// If we have a struct reference but no actual struct,
// we need to resolve it
if field.structReference != nil && field.Struct == nil {
fqn := field.structReference.FullyQualifiedName()
println("Need to resolve struct reference: ", fqn)
// Check the cache for the struct
structPointer, err := p.ParseStruct(field.structReference.Package, field.structReference.Name)
if err != nil {
return err
}
field.Struct = structPointer
if field.Struct != nil {
// Save the fact that the struct is used as data
field.Struct.UsedAsData = true
println("Resolved struct reference:", fqn)
// Resolve *its* references
err = p.resolveStructReferences(field.Struct)
if err != nil {
return err
}
} else {
println("Unable to resolve struct reference:", fqn)
}
}
}
return nil
}

View File

@@ -0,0 +1,5 @@
package parser
func (p *Parser) getFunctionReturnType(packageName string, functionName string) *Struct {
return nil
}

106
v2/pkg/parser/method.go Normal file
View File

@@ -0,0 +1,106 @@
package parser
import (
"go/ast"
"strings"
)
// Method defines a struct method
type Method struct {
Name string
Comments []string
Inputs []*Field
Returns []*Field
}
func (p *Parser) parseStructMethods(boundStruct *Struct) error {
for _, fileAst := range boundStruct.Package.Syntax {
// Track errors
var parseError error
ast.Inspect(fileAst, func(n ast.Node) bool {
if funcDecl, ok := n.(*ast.FuncDecl); ok {
if funcDecl.Recv == nil {
return true
}
// This is a struct method
for _, field := range funcDecl.Recv.List {
switch f := field.Type.(type) {
case *ast.StarExpr:
// This is a struct pointer method
ident, ok := f.X.(*ast.Ident) // _ ?
if !ok {
continue
}
// Check this method is for this struct
if ident.Name != boundStruct.Name {
continue
}
// We want to ignore Internal functions
if p.internalMethods.Contains(funcDecl.Name.Name) {
continue
}
// If this method is not Public, ignore
if string(funcDecl.Name.Name[0]) != strings.ToUpper((string(funcDecl.Name.Name[0]))) {
continue
}
// Create our struct
structMethod := &Method{
Name: funcDecl.Name.Name,
Comments: p.parseComments(funcDecl.Doc),
}
// Save the input parameters
if funcDecl.Type.Params != nil {
for _, inputField := range funcDecl.Type.Params.List {
fields, err := p.parseField(inputField, boundStruct.Package.Name)
if err != nil {
parseError = err
return false
}
structMethod.Inputs = append(structMethod.Inputs, fields...)
}
}
// Save the output parameters
if funcDecl.Type.Results != nil {
for _, outputField := range funcDecl.Type.Results.List {
fields, err := p.parseField(outputField, boundStruct.Package.Name)
if err != nil {
parseError = err
return false
}
structMethod.Returns = append(structMethod.Returns, fields...)
}
}
// Append this method to the parsed struct
boundStruct.Methods = append(boundStruct.Methods, structMethod)
default:
// Unsupported
continue
}
}
}
return true
})
// If we got an error, return it
if parseError != nil {
return parseError
}
}
return nil
}

View File

@@ -0,0 +1,93 @@
package parser
import (
"go/ast"
)
// getCachedStruct attempts to get an already parsed struct from the
// struct cache
func (p *Parser) getCachedStruct(packageName string, structName string) *Struct {
fqn := packageName + "." + structName
return p.parsedStructs[fqn]
}
// ParseStruct will attempt to parse the given struct using
// the package it references
func (p *Parser) ParseStruct(packageName string, structName string) (*Struct, error) {
// Check the cache
result := p.getCachedStruct(packageName, structName)
if result != nil {
return result, nil
}
// Find the package
pkg := p.getPackageByName(packageName)
if pkg == nil {
// TODO: Find package via imports?
println("Cannot find package", packageName)
return nil, nil
}
// Iterate through the whole package looking for the bound structs
for _, fileAst := range pkg.Syntax {
// Track errors
var parseError error
ast.Inspect(fileAst, func(n ast.Node) bool {
if genDecl, ok := n.(*ast.GenDecl); ok {
for _, spec := range genDecl.Specs {
if typeSpec, ok := spec.(*ast.TypeSpec); ok {
if structType, ok := typeSpec.Type.(*ast.StructType); ok {
structDefinitionName := typeSpec.Name.Name
if structDefinitionName == structName {
// Create the new struct
result = p.newStruct(pkg, structDefinitionName)
// Save comments
result.Comments = p.parseComments(genDecl.Doc)
parseError = p.parseStructMethods(result)
if parseError != nil {
return false
}
// Parse the struct fields
parseError = p.parseStructFields(structType, result)
// Cache this struct
key := result.FullyQualifiedName()
p.parsedStructs[key] = result
return false
}
}
}
}
}
return true
})
// If we got an error, return it
if parseError != nil {
return nil, parseError
}
}
return result, nil
}
func (p *Parser) parseStructFields(structType *ast.StructType, boundStruct *Struct) error {
// Parse the fields
for _, field := range structType.Fields.List {
fields, err := p.parseField(field, boundStruct.Package.Name)
if err != nil {
return err
}
boundStruct.Fields = append(boundStruct.Fields, fields...)
}
return nil
}

168
v2/pkg/parser/parser.go Normal file
View File

@@ -0,0 +1,168 @@
package parser
import (
"fmt"
"go/token"
"github.com/davecgh/go-spew/spew"
"github.com/leaanthony/slicer"
"github.com/pkg/errors"
"golang.org/x/tools/go/packages"
)
type Parser struct {
// Placeholders for Go's parser
goPackages []*packages.Package
fileSet *token.FileSet
internalMethods *slicer.StringSlicer
// This is a map of structs that have been parsed
// The key is <package>.<structname>
parsedStructs map[string]*Struct
// The list of struct names that are bound
BoundStructReferences []*StructReference
// The list of structs that are bound
BoundStructs []*Struct
}
func NewParser() *Parser {
return &Parser{
fileSet: token.NewFileSet(),
internalMethods: slicer.String([]string{"WailsInit", "WailsShutdown"}),
parsedStructs: make(map[string]*Struct),
}
}
// ParseProject will parse the Wails project in the given directory
func (p *Parser) ParseProject(dir string) error {
var err error
err = p.loadPackages(dir)
if err != nil {
return err
}
err = p.findBoundStructs()
if err != nil {
return err
}
err = p.parseBoundStructs()
if err != nil {
return err
}
spew.Dump(p.BoundStructs)
println("******* Parsed Structs *******")
fmt.Printf("%+v\n", p.parsedStructs)
return err
}
func (p *Parser) loadPackages(projectPath string) error {
mode := packages.NeedName |
packages.NeedFiles |
packages.NeedSyntax |
packages.NeedTypes |
packages.NeedImports |
packages.NeedTypesInfo
cfg := &packages.Config{Fset: p.fileSet, Mode: mode, Dir: projectPath}
pkgs, err := packages.Load(cfg, "./...")
if err != nil {
return errors.Wrap(err, "Problem loading packages")
}
// Check for errors
var parseError error
for _, pkg := range pkgs {
for _, err := range pkg.Errors {
if parseError == nil {
parseError = errors.New(err.Error())
} else {
parseError = errors.Wrap(parseError, err.Error())
}
}
}
if parseError != nil {
return parseError
}
p.goPackages = pkgs
return nil
}
func (p *Parser) getPackageByName(packageName string) *packages.Package {
for _, pkg := range p.goPackages {
if pkg.Name == packageName {
return pkg
}
}
return nil
}
func (p *Parser) getWailsImportName(pkg *packages.Package) (string, bool) {
// Scan the imports for the wails v2 import
for key, details := range pkg.Imports {
if key == "github.com/wailsapp/wails/v2" {
return details.Name, true
}
}
return "", false
}
// findBoundStructs will search through the Wails project looking
// for which structs have been bound using the `Bind()` method
func (p *Parser) findBoundStructs() error {
// Try each of the packages to find the Bind() calls
for _, pkg := range p.goPackages {
// Does this package import Wails?
wailsImportName, imported := p.getWailsImportName(pkg)
if !imported {
continue
}
// Do we create an app using CreateApp?
appVariableName, created := p.getApplicationVariableName(pkg, wailsImportName)
if !created {
continue
}
boundStructReferences := p.findBoundStructsInPackage(pkg, appVariableName)
p.BoundStructReferences = append(p.BoundStructReferences, boundStructReferences...)
}
return nil
}
func (p *Parser) parseBoundStructs() error {
// Iterate the structs
for _, boundStructReference := range p.BoundStructReferences {
// Parse the struct
boundStruct, err := p.ParseStruct(boundStructReference.Package, boundStructReference.Name)
if err != nil {
return err
}
p.BoundStructs = append(p.BoundStructs, boundStruct)
}
// Resolve the references between the structs
// This is when a field of one struct is a struct type
for _, boundStruct := range p.BoundStructs {
err := p.resolveStructReferences(boundStruct)
if err != nil {
return err
}
}
return nil
}

View File

@@ -0,0 +1,46 @@
package parser
import (
"testing"
"github.com/leaanthony/slicer"
"github.com/matryer/is"
"github.com/wailsapp/wails/v2/internal/fs"
)
func TestParser(t *testing.T) {
is := is.New(t)
// Local project dir
projectDir := fs.RelativePath("./testproject")
p := NewParser()
// Check parsing worked
err := p.ParseProject(projectDir)
is.NoErr(err)
// Expected structs
expectedBoundStructs := slicer.String()
expectedBoundStructs.Add("main.Basic", "mypackage.Manager")
// We expect these to be the same length
is.Equal(expectedBoundStructs.Length(), len(p.BoundStructs))
// Check bound structs
for _, boundStruct := range p.BoundStructs {
// Check the names are correct
fqn := boundStruct.FullyQualifiedName()
is.True(expectedBoundStructs.Contains(fqn))
// Check that the structs have comments
is.True(len(boundStruct.Comments) > 0)
// Check that the structs have methods
is.True(len(boundStruct.Methods) > 0)
}
}

109
v2/pkg/parser/struct.go Normal file
View File

@@ -0,0 +1,109 @@
package parser
import (
"fmt"
"go/ast"
"golang.org/x/tools/go/packages"
)
type Struct struct {
Package *packages.Package
Name string
Comments []string
Fields []*Field
Methods []*Method
// This is true when this struct is used as a datatype
UsedAsData bool
}
// newStruct creates a new struct and stores in the cache
func (p *Parser) newStruct(pkg *packages.Package, name string) *Struct {
result := &Struct{
Package: pkg,
Name: name,
}
return result
}
// FullyQualifiedName returns the fully qualified name of this struct
func (s *Struct) FullyQualifiedName() string {
return s.Package.Name + "." + s.Name
}
func (p *Parser) parseStructNameFromStarExpr(starExpr *ast.StarExpr) (string, string, error) {
pkg := ""
name := ""
// Determine the FQN
switch x := starExpr.X.(type) {
case *ast.SelectorExpr:
switch i := x.X.(type) {
case *ast.Ident:
pkg = i.Name
default:
return "", "", fmt.Errorf("Unsupported Selector expression: %+v", i)
}
name = x.Sel.Name
case *ast.StarExpr:
switch s := x.X.(type) {
case *ast.Ident:
name = s.Name
default:
return "", "", fmt.Errorf("Unsupported Star expression: %+v", s)
}
case *ast.Ident:
name = x.Name
default:
return "", "", fmt.Errorf("Unsupported Star.X expression: %+v", x)
}
return pkg, name, nil
}
// StructReference defines a reference to a fully qualified struct
type StructReference struct {
Package string
Name string
}
func newStructReference(packageName string, structName string) *StructReference {
return &StructReference{Package: packageName, Name: structName}
}
// FullyQualifiedName returns a string representing the struct reference
func (s *StructReference) FullyQualifiedName() string {
return s.Package + "." + s.Name
}
func (p *Parser) resolveStructReferences(boundStruct *Struct) error {
var err error
// Resolve field references
err = p.resolveFieldReferences(boundStruct.Fields)
if err != nil {
return nil
}
// Check if method fields need resolving
for _, method := range boundStruct.Methods {
// Resolve method inputs
err = p.resolveFieldReferences(method.Inputs)
if err != nil {
return nil
}
// Resolve method outputs
err = p.resolveFieldReferences(method.Returns)
if err != nil {
return nil
}
}
return nil
}

View File

@@ -0,0 +1,59 @@
package main
import (
"fmt"
wails "github.com/wailsapp/wails/v2"
)
// Basic application struct
type Basic struct {
runtime *wails.Runtime
}
// // Another application struct
// type Another struct {
// runtime *wails.Runtime
// }
// func (a *Another) Doit() {
// }
// // newBasicPointer creates a new Basic application struct
// func newBasicPointer() *Basic {
// return &Basic{}
// }
// // newBasic creates a new Basic application struct
// func newBasic() Basic {
// return Basic{}
// }
// WailsInit is called at application startup
func (b *Basic) WailsInit(runtime *wails.Runtime) error {
// Perform your setup here
b.runtime = runtime
runtime.Window.SetTitle("jsbundle")
return nil
}
// WailsShutdown is called at application termination
func (b *Basic) WailsShutdown() {
// Perform your teardown here
}
// // NewPerson creates a new person
// func (b *Basic) NewPerson(name string, age int) *mypackage.Person {
// return &mypackage.Person{Name: name, Age: age}
// }
// Greet returns a greeting for the given name
func (b *Basic) Greet(name string) string {
return fmt.Sprintf("Hello %s!", name)
}
// // RemovePerson Removes the given person
// func (b *Basic) RemovePerson(p *mypackage.Person) {
// // dummy
// }

View File

@@ -0,0 +1,9 @@
module testproject
go 1.13
require (
github.com/wailsapp/wails/v2 v2.0.0-alpha
)
replace github.com/wailsapp/wails/v2 v2.0.0-alpha => /home/lea/Data/projects/wails/v2

View File

@@ -0,0 +1,83 @@
github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/leaanthony/clir v1.0.4/go.mod h1:k/RBkdkFl18xkkACMCLt09bhiZnrGORoxmomeMvDpE0=
github.com/leaanthony/gosod v0.0.4/go.mod h1:nGMCb1PJfXwBDbOAike78jEYlpqge+xUKFf0iBKjKxU=
github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/matryer/is v1.4.0/go.mod h1:8I/i5uYgLzgsgEloJE1U6xx5HkBQpAZvepWuujKwMRU=
github.com/matryer/try v0.0.0-20161228173917-9ac251b645a2/go.mod h1:0KeJpeMD6o+O4hW7qJOT7vyQPKrWmj26uf5wMc/IiIs=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/olekukonko/tablewriter v0.0.4/go.mod h1:zq6QwlOf5SlnkVbMSr5EoBv3636FWnp+qbPhuoO21uA=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/tdewolff/minify v2.3.6+incompatible/go.mod h1:9Ov578KJUmAWpS6NeZwRZyT56Uf6o3Mcz9CEsg8USYs=
github.com/tdewolff/minify/v2 v2.9.5/go.mod h1:jshtBj/uUJH6JX1fuxTLnnHOA1RVJhF5MM+leJzDKb4=
github.com/tdewolff/parse v2.3.4+incompatible/go.mod h1:8oBwCsVmUkgHO8M5iCzSIDtpzXOT0WXX9cWhz+bIzJQ=
github.com/tdewolff/parse/v2 v2.5.3/go.mod h1:WzaJpRSbwq++EIQHYIRTpbYKNA3gn9it1Ik++q4zyho=
github.com/tdewolff/test v1.0.6/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/xyproto/xpm v1.2.1/go.mod h1:cMnesLsD0PBXLgjDfTDEaKr8XyTFsnP1QycSqRw7BiY=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200902012652-d1954cc86c82/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
nhooyr.io/websocket v1.8.6/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=

View File

@@ -0,0 +1,21 @@
package main
import (
"testproject/mypackage"
"github.com/wailsapp/wails/v2"
)
func main() {
// Create application with options
app := wails.CreateApp("jsbundle", 1024, 768)
/***** Struct Literal *****/
// Local struct pointer literal *WORKING*
app.Bind(&Basic{})
// External struct pointer literal
app.Bind(&mypackage.Manager{})
}

View File

@@ -0,0 +1,36 @@
// Package mypackage does all the things a mypackage can do
package mypackage
type Address struct {
Number int
Street string
Town string
Postcode string
}
// Person defines a Person in the application
type Person struct {
// Name is a name
Name string
Age int
Address *Address
}
// Manager is the Mr Manager
type Manager struct {
Name string
TwoIC *Person
}
// Hire me some peoples!
func (m *Manager) Hire(name, test string, bob int) *Person {
return &Person{Name: name}
}
// func NewManagerPointer() *Manager {
// return &Manager{}
// }
// func NewManager() Manager {
// return Manager{}
// }