Compare commits

...

31 Commits

Author SHA1 Message Date
Adam Tenderholt 536ae4ca68 Feature/v3 parser: expand TS model generation tests & some fixes (#2485)
* v3 parser: add tests for model generation

* v3 parser: use single quotes for got model.ts

* v3 parser: fixes for some failing tests

* v3 parser: misc simplification and cleanup

* v3 parser: fix model tests when no structs returned

* v3 parser: fix last failing test case

* Update contributors list

* v3 parser: update README

* Revert "Update contributors list"

This reverts commit f429d2ba890020d7ff0772e6207830508261b489.

* Changelog: add line about my contribution
2023-03-23 07:15:14 +11:00
Lea Anthony e302d11f12 Update module deps 2023-03-09 08:23:20 +11:00
Lea Anthony eb670f4ba1 Merge branch 'master' into feature/v3-parser
# Conflicts:
#	v3/go.mod
#	v3/go.sum
2023-03-09 08:22:47 +11:00
Lea Anthony 5e0ce40b41 Update TODO 2023-03-09 08:21:37 +11:00
Lea Anthony 26530a0f5a Fix reserve word check.
Add model generation.
Warn if field is unexported in the Go struct
2023-03-07 19:48:30 +11:00
Lea Anthony 7340247e25 Create bindings file per package
Improved bindings tests
2023-03-07 18:22:33 +11:00
Lea Anthony f1a7f1b781 Improved bindings generation 2023-03-06 20:54:04 +11:00
Lea Anthony 71aa7c9731 Initial bindings.js generation 2023-03-03 19:54:12 +11:00
Lea Anthony 868b769e7f Initial bindings generation 2023-03-01 21:31:29 +11:00
Lea Anthony 8dc8c8e15e Merge remote-tracking branch 'origin/feature/v3-parser' into feature/v3-parser 2023-02-28 20:35:39 +11:00
Adam Tenderholt da90e74268 v3 parser: initial work on model generation w/ templates (#2428)
* v3 parser: initial work on model generation w/ templates

* v3 parser: expand models to namespaces
2023-02-28 20:35:18 +11:00
Lea Anthony 443ea46d1d Example bindings 2023-02-27 20:05:54 +11:00
Lea Anthony 00c458f948 Implement basic binding 2023-02-26 20:49:29 +11:00
Lea Anthony 33855ff01d Add tests for bound structs returned by function calls. 2023-02-26 19:18:47 +11:00
Lea Anthony f9ffe915f2 Add bindings hook 2023-02-26 15:06:05 +11:00
Lea Anthony 91676080eb Support binding variables that were assigned by functions 2023-02-26 13:12:30 +11:00
Lea Anthony 6afb5260a7 Refactor parsing functions 2023-02-26 08:56:27 +11:00
Adam Tenderholt 0f80f031fd v3 parser: add some more test cases (functions) (#2422)
* [v3] add test case for parser (create struct from func)

* [v3] add another test case for parser (func in other pkg) + misc
2023-02-26 07:46:26 +11:00
Lea Anthony ecc1791420 Support bound variables (struct literals)
Factor out unaryexpression parsing
Fix package bleed between tests
2023-02-25 09:47:50 +11:00
Lea Anthony 4a8917ecbc Add nested anonymous struct test 2023-02-25 08:27:36 +11:00
Lea Anthony cc1a6a3d50 Support anonymous struct fields 2023-02-25 08:24:58 +11:00
Lea Anthony cd11c0a83c Support references to structs in other packages 2023-02-24 21:15:39 +11:00
Lea Anthony 8fd0e06c24 Use package path instead of name 2023-02-23 20:26:15 +11:00
Lea Anthony 4e5be36459 Parse structs bound from other packages 2023-02-22 20:36:30 +11:00
Lea Anthony 6bfd654ec8 Tidy up. More tests. 2023-02-21 17:10:36 +11:00
Lea Anthony dc0d99a8e9 Cover all type combinations
Fix bug in pointer type resolution
2023-02-21 07:52:29 +11:00
Lea Anthony b606561f8d Move struct cache into parsed package
Fix bug in package path calculation
2023-02-21 07:18:08 +11:00
Lea Anthony d0769ecd1c Parse Models
Support recursive fields
Add loads of tests
2023-02-20 20:36:58 +11:00
Lea Anthony 95bb15eef4 [v3] MUCH Improved parser for bound structs 2023-02-19 20:59:03 +11:00
Lea Anthony 93aa8345dc [v3] Improved parser for bound structs 2023-02-17 21:01:16 +11:00
Lea Anthony e1279a054f [v3] Improved parser for bound structs 2023-02-17 20:57:31 +11:00
73 changed files with 5460 additions and 852 deletions
@@ -61,7 +61,7 @@ var jsReservedKeywords []string = []string{
"typeof",
"var",
"void",
"volotile",
"volatile",
"while",
"with",
"yield",
+2 -2
View File
@@ -4,8 +4,8 @@ Informal and incomplete list of things needed in v3.
## General
- [ ] Generate Bindings
- [ ] Generate TS Models
- [x] Generate Bindings
- [x] Generate TS Models
- [ ] Dev Mode
- [ ] Generate Info.Plist from `info.json`
+16
View File
@@ -0,0 +1,16 @@
package main
type Person struct {
name string
}
type GreetService struct {
}
func (*GreetService) Greet(name string) string {
return "Hello " + name
}
func (*GreetService) GreetPerson(person Person) string {
return "Hello " + person.name
}
+10
View File
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
HELLO!
</body>
</html>
+43
View File
@@ -0,0 +1,43 @@
// @ts-check
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Ă‚ MODIWL
// This file is automatically generated. DO NOT EDIT
import {main} from './models';
function GreetService(method) {
return {
packageName: "main",
serviceName: "GreetService",
methodName: method,
args: Array.prototype.slice.call(arguments, 1),
};
}
/**
* GreetService.Greet
*
* @param name {string}
* @returns {Promise<string>}
**/
function Greet(name) {
return wails.Call(GreetService("Greet", name));
}
/**
* GreetService.GreetPerson
*
* @param person {main.Person}
* @returns {Promise<string>}
**/
function GreetPerson(person) {
return wails.Call(GreetService("GreetPerson", person));
}
window.go = window.go || {};
window.go.main = {
GreetService: {
Greet,
GreetPerson,
},
};
+21
View File
@@ -0,0 +1,21 @@
module binding
go 1.20
require github.com/wailsapp/wails/v3 v3.0.0-alpha.0
require (
github.com/imdario/mergo v0.3.12 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/leaanthony/slicer v1.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/samber/lo v1.37.0 // indirect
github.com/wailsapp/mimetype v1.4.1 // indirect
github.com/wailsapp/wails/v2 v2.3.2-0.20230117193915-45c3a501d9e6 // indirect
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 // indirect
golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
)
replace github.com/wailsapp/wails/v3 => ../..
replace github.com/wailsapp/wails/v2 => ../../../v2
+20 -2
View File
@@ -1,14 +1,31 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/leaanthony/slicer v1.5.0 h1:aHYTN8xbCCLxJmkNKiLB6tgcMARl4eWmH9/F+S/0HtY=
github.com/leaanthony/slicer v1.5.0/go.mod h1:FwrApmf8gOrpzEWM2J/9Lh79tyq8KTX5AzRtwV7m4AY=
github.com/matryer/is v1.4.0 h1:sosSmIWwkYITGrxZ25ULNDeKiMNzFSr4V/eqBQP0PeE=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/samber/lo v1.37.0 h1:XjVcB8g6tgUp8rsPsJ2CvhClfImrpL04YpQHXeHPhRw=
github.com/samber/lo v1.37.0/go.mod h1:9vaz2O4o8oOnK23pd2TrXufcbdbJIa3b6cstBWKpopA=
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.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
github.com/wailsapp/mimetype v1.4.1/go.mod h1:9aV5k31bBOv5z6u+QP8TltzvNGJPmNJD4XlAL3U+j3o=
github.com/wailsapp/wails/v2 v2.3.2-0.20230117193915-45c3a501d9e6 h1:Wn+nhnS+VytzE0PegUzSh4T3hXJCtggKGD/4U5H9+wQ=
github.com/wailsapp/wails/v2 v2.3.2-0.20230117193915-45c3a501d9e6/go.mod h1:zlNLI0E2c2qA6miiuAHtp0Bac8FaGH0tlhA19OssR/8=
github.com/wailsapp/wails/v3 v3.0.0-alpha.0 h1:T5gqG98Xr8LBf69oxlPkhpsFD59w2SnqUZk6XHj8Zoc=
github.com/wailsapp/wails/v3 v3.0.0-alpha.0/go.mod h1:OAfO5bP0TSUvCIHZYc6Dqfow/9RqxzHvYtmhWPpo1c0=
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 h1:RjggHMcaTVp0LOVZcW0bo8alwHrOaCrGUDgfWUHhnN4=
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
@@ -20,3 +37,4 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+12 -6
View File
@@ -1,25 +1,31 @@
package main
import (
"embed"
_ "embed"
"log"
"github.com/wailsapp/wails/v3/examples/binding/services"
"github.com/wailsapp/wails/v3/pkg/application"
)
type localStruct struct{}
//go:embed assets
var assets embed.FS
func main() {
app := application.New(application.Options{
Bind: []interface{}{
&localStruct{},
&services.GreetService{},
&GreetService{},
},
Mac: application.MacOptions{
ApplicationShouldTerminateAfterLastWindowClosed: true,
},
})
app.NewWebviewWindow()
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
Assets: application.AssetOptions{
FS: assets,
},
})
err := app.Run()
+24
View File
@@ -0,0 +1,24 @@
// @ts-check
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Ă‚ MODIWL
// This file is automatically generated. DO NOT EDIT
export namespace main {
export class Person {
name: string; // Warning: this is unexported in the Go struct.
static createFrom(source: any = {}) {
return new Person(source);
}
constructor(source: any = {}) {
if ('string' === typeof source) {
source = JSON.parse(source);
}
this.name = source["name"]
}
}
}
-8
View File
@@ -1,8 +0,0 @@
// Code generated by tygo. DO NOT EDIT.
//////////
// source: person.go
export interface Person {
Name: string;
}
-5
View File
@@ -1,5 +0,0 @@
package models
type Person struct {
Name string
}
@@ -1,23 +0,0 @@
package services
import (
"github.com/wailsapp/wails/v3/examples/binding/models"
)
type GreetService struct {
SomeVariable int
lowercase string
Parent *models.Person
}
func (*GreetService) Greet(name string) string {
return "Hello " + name
}
func (g *GreetService) GetPerson() *models.Person {
return g.Parent
}
func (g *GreetService) SetPerson(person *models.Person) {
g.Parent = person
}
-9
View File
@@ -1,9 +0,0 @@
// Code generated by tygo. DO NOT EDIT.
//////////
// source: GreetService.go
export interface GreetService {
SomeVariable: number /* int */;
Parent?: any /* models.Person */;
}
+1 -2
View File
@@ -17,7 +17,7 @@ func main() {
},
})
// Create window
app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
myWindow := app.NewWebviewWindowWithOptions(&application.WebviewWindowOptions{
Title: "Plain Bundle",
CSS: `body { background-color: rgba(255, 255, 255, 0); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; user-select: none; -ms-user-select: none; -webkit-user-select: none; } .main { color: white; margin: 20%; }`,
Mac: application.MacWindow{
@@ -25,7 +25,6 @@ func main() {
Backdrop: application.MacBackdropTranslucent,
TitleBar: application.MacTitleBarHiddenInsetUnified,
},
URL: "/",
Assets: application.AssetOptions{
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+1 -5
View File
@@ -4,6 +4,7 @@ go 1.19
require (
github.com/go-task/task/v3 v3.20.0
github.com/google/go-cmp v0.5.9
github.com/jackmordaunt/icns/v2 v2.2.1
github.com/json-iterator/go v1.1.12
github.com/leaanthony/clir v1.6.0
@@ -12,17 +13,14 @@ require (
github.com/matryer/is v1.4.0
github.com/pterm/pterm v0.12.51
github.com/samber/lo v1.37.0
github.com/stretchr/testify v1.8.1
github.com/tc-hib/winres v0.1.6
github.com/wailsapp/wails/v2 v2.3.2-0.20230117193915-45c3a501d9e6
golang.org/x/tools v0.1.12
)
require (
atomicgo.dev/cursor v0.1.1 // indirect
atomicgo.dev/keyboard v0.2.8 // indirect
github.com/containerd/console v1.0.3 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
github.com/gookit/color v1.5.2 // indirect
@@ -38,7 +36,6 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/radovskyb/watcher v1.0.7 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/sajari/fuzzy v1.0.0 // indirect
@@ -46,7 +43,6 @@ require (
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 // indirect
golang.org/x/image v0.5.0 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/net v0.7.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.5.0 // indirect
+1 -4
View File
@@ -26,6 +26,7 @@ github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg78
github.com/go-task/task/v3 v3.20.0 h1:pTavuhP+AiEpKLzh5I6Lja9Ux7ypYO5QMsEPTbhYEDc=
github.com/go-task/task/v3 v3.20.0/go.mod h1:y7rWakbLR5gFElGgo6rA2dyr6vU/zNIDVfn3S4Of6OI=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
github.com/gookit/color v1.5.0/go.mod h1:43aQb+Zerm/BWh2GnrgOQm7ffz7tvQXEKV6BFMl7wAo=
@@ -111,7 +112,6 @@ github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z
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/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
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/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
@@ -120,7 +120,6 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/tc-hib/winres v0.1.6 h1:qgsYHze+BxQPEYilxIz/KCQGaClvI2+yLBAZs+3+0B8=
github.com/tc-hib/winres v0.1.6/go.mod h1:pe6dOR40VOrGz8PkzreVKNvEKnlE8t4yR8A8naL+t7A=
github.com/wailsapp/mimetype v1.4.1 h1:pQN9ycO7uo4vsUUuPeHEYoUkLVkaRntMnHJxVwYhwHs=
@@ -137,7 +136,6 @@ golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+o
golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.5.0 h1:5JMiNunQeQw++mMOz48/ISeNu3Iweh/JaZU8ZLqHRrI=
golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
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=
@@ -181,7 +179,6 @@ golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
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.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+5 -32
View File
@@ -1,42 +1,15 @@
package commands
import (
"bytes"
"fmt"
"os"
"github.com/wailsapp/wails/v3/internal/parser"
)
import "github.com/wailsapp/wails/v3/internal/parser"
type GenerateBindingsOptions struct {
Silent bool `name:"silent" description:"Silent mode"`
ModelsFilename string `name:"m" description:"The filename for the models file" default:"models.ts"`
BindingsFilename string `name:"b" description:"The filename for the bindings file" default:"bindings.js"`
ProjectDirectory string `name:"d" description:"The project directory" default:"."`
ProjectDirectory string `name:"p" description:"The project directory" default:"."`
OutputDirectory string `name:"d" description:"The output directory" default:"."`
}
func GenerateBindings(options *GenerateBindingsOptions) error {
parserContext, err := parser.ParseDirectory(options.ProjectDirectory)
if err != nil {
return fmt.Errorf("error parsing project: %v", err)
}
// Generate models
modelsData, err := parser.GenerateModels(parserContext)
if err != nil {
return fmt.Errorf("error generating models: %v", err)
}
var modelsFileData bytes.Buffer
modelsFileData.WriteString(`// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Ă‚ MODIWL
// This file is automatically generated. DO NOT EDIT
`)
modelsFileData.Write(modelsData)
err = os.WriteFile(options.ModelsFilename, modelsFileData.Bytes(), 0755)
if err != nil {
return fmt.Errorf("error writing models file: %v", err)
}
println("Generated models file '" + options.ModelsFilename + "'")
return nil
return parser.GenerateBindingsAndModels(options.ProjectDirectory, options.OutputDirectory)
}
+47 -3
View File
@@ -7,17 +7,61 @@ This package contains the static analyser used for parsing Wails projects so tha
## Implemented
- [x] Parsing of structs
- [x] Generation of models
- [ ] Bound types
- [x] Struct Literal Pointer
- [ ] Variable
- [ ] Assignment
- [x] Struct Literal Pointer
- [ ] Function
- [ ] Same package
- [ ] Different package
- [ ] Function
- [x] Parsing of bound methods
- [x] Method names
- [x] Method parameters
- [x] Zero parameters
- [x] Single input parameter
- [x] Single output parameter
- [x] Multiple input parameters
- [x] Multiple output parameters
- [x] Named output parameters
- [x] int/8/16/32/64
- [x] Pointer
- [x] uint/8/16/32/64
- [x] Pointer
- [x] float
- [x] Pointer
- [x] string
- [x] Pointer
- [x] bool
- [x] Pointer
- [x] Struct
- [x] Pointer
- [x] Slices
- [x] Pointer
- [x] Maps
- [x] Pointer
- [x] Model Parsing
- [x] In same package
- [x] In different package
- [x] Multiple named fields, e.g. one,two,three string
- [x] Scalars
- [x] Arrays
- [x] Maps
- [x] Structs
- [x] Recursive
- [x] Anonymous
- [ ] Generation of models
- [x] Scalars
- [ ] Arrays
- [ ] Maps
- [x] Structs
- [ ] Generation of bindings
## Limitations
There are many ways to write a Go program so there are many different program structures that we would need to support. This is a work in progress and will be improved over time. The current limitations are:
There are many ways to write a Go program so there are many program structures that we would need to support. This is a work in progress and will be improved over time. The current limitations are:
- The call to `application.New()` must be in the `main` package
- Bound structs must be declared as struct literals
+285
View File
@@ -0,0 +1,285 @@
package parser
import (
"sort"
"strconv"
"strings"
"github.com/samber/lo"
)
const header = `// @ts-check
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Ă‚ MODIWL
// This file is automatically generated. DO NOT EDIT
`
const helperTemplate = `function {{structName}}(method) {
return {
packageName: "{{packageName}}",
serviceName: "{{structName}}",
methodName: method,
args: Array.prototype.slice.call(arguments, 1),
};
}
`
func GenerateHelper(packageName, structName string) string {
result := strings.ReplaceAll(helperTemplate, "{{packageName}}", packageName)
result = strings.ReplaceAll(result, "{{structName}}", structName)
return result
}
const bindingTemplate = `
/**
* {{structName}}.{{methodName}}
* Comments
* @param name {string}
* @returns {Promise<string>}
**/
function {{methodName}}({{inputs}}) {
return wails.Call({{structName}}("{{methodName}}"{{args}}));
}
`
var reservedWords = []string{
"abstract",
"arguments",
"await",
"boolean",
"break",
"byte",
"case",
"catch",
"char",
"class",
"const",
"continue",
"debugger",
"default",
"delete",
"do",
"double",
"else",
"enum",
"eval",
"export",
"extends",
"false",
"final",
"finally",
"float",
"for",
"function",
"goto",
"if",
"implements",
"import",
"in",
"instanceof",
"int",
"interface",
"let",
"long",
"native",
"new",
"null",
"package",
"private",
"protected",
"public",
"return",
"short",
"static",
"super",
"switch",
"synchronized",
"this",
"throw",
"throws",
"transient",
"true",
"try",
"typeof",
"var",
"void",
"volatile",
"while",
"with",
"yield",
"object",
}
func sanitiseJSVarName(name string) string {
// if the name is a reserved word, prefix with an
// underscore
if lo.Contains(reservedWords, name) {
return "_" + name
}
return name
}
func GenerateBinding(structName string, method *BoundMethod) (string, []string) {
var models []string
result := strings.ReplaceAll(bindingTemplate, "{{structName}}", structName)
result = strings.ReplaceAll(result, "{{methodName}}", method.Name)
comments := strings.TrimSpace(method.DocComment)
result = strings.ReplaceAll(result, "Comments", comments)
var params string
for _, input := range method.Inputs {
pkgName := getPackageName(input)
if pkgName != "" {
models = append(models, pkgName)
}
params += " * @param " + sanitiseJSVarName(input.Name) + " {" + input.JSType() + "}\n"
}
params = strings.TrimSuffix(params, "\n")
if len(params) == 0 {
params = " *"
}
result = strings.ReplaceAll(result, " * @param name {string}", params)
var inputs string
for _, input := range method.Inputs {
pkgName := getPackageName(input)
if pkgName != "" {
models = append(models, pkgName)
}
inputs += sanitiseJSVarName(input.Name) + ", "
}
inputs = strings.TrimSuffix(inputs, ", ")
args := inputs
if len(args) > 0 {
args = ", " + args
}
result = strings.ReplaceAll(result, "{{inputs}}", inputs)
result = strings.ReplaceAll(result, "{{args}}", args)
// outputs
var returns string
if len(method.Outputs) == 0 {
returns = " * @returns {Promise<void>}"
} else {
returns = " * @returns {Promise<"
for _, output := range method.Outputs {
pkgName := getPackageName(output)
if pkgName != "" {
models = append(models, pkgName)
}
jsType := output.JSType()
if jsType == "error" {
jsType = "void"
}
returns += jsType + ", "
}
returns = strings.TrimSuffix(returns, ", ")
returns += ">}"
}
result = strings.ReplaceAll(result, " * @returns {Promise<string>}", returns)
return result, lo.Uniq(models)
}
func getPackageName(input *Parameter) string {
if !input.Type.IsStruct {
return ""
}
result := input.Type.Package
if result == "" {
result = "main"
}
return result
}
func normalisePackageNames(packageNames []string) map[string]string {
// We iterate over the package names and determine if any of them
// have a forward slash. If this is the case, we assume that the
// package name is the last element of the path. If this has already
// been found, then we need to add a digit to the end of the package
// name to make it unique. We return a map of the original package
// name to the new package name.
var result = make(map[string]string)
var packagesConverted = make(map[string]struct{})
var count = 1
for _, packageName := range packageNames {
var originalPackageName = packageName
if strings.Contains(packageName, "/") {
parts := strings.Split(packageName, "/")
packageName = parts[len(parts)-1]
}
if _, ok := packagesConverted[packageName]; ok {
// We've already seen this package name. Add a digit
// to the end of the package name to make it unique
count += 1
packageName += strconv.Itoa(count)
}
packagesConverted[packageName] = struct{}{}
result[originalPackageName] = packageName
}
return result
}
func GenerateBindings(bindings map[string]map[string][]*BoundMethod) map[string]string {
var result = make(map[string]string)
var normalisedPackageNames = normalisePackageNames(lo.Keys(bindings))
// sort the bindings keys
packageNames := lo.Keys(bindings)
sort.Strings(packageNames)
for _, packageName := range packageNames {
var allModels []string
packageBindings := bindings[packageName]
structNames := lo.Keys(packageBindings)
sort.Strings(structNames)
for _, structName := range structNames {
result[normalisedPackageNames[packageName]] += GenerateHelper(normalisedPackageNames[packageName], structName)
methods := packageBindings[structName]
sort.Slice(methods, func(i, j int) bool {
return methods[i].Name < methods[j].Name
})
for _, method := range methods {
thisBinding, models := GenerateBinding(structName, method)
result[normalisedPackageNames[packageName]] += thisBinding
allModels = append(allModels, models...)
}
}
result[normalisedPackageNames[packageName]] += `
window.go = window.go || {};
`
// Iterate over the sorted struct keys
result[normalisedPackageNames[packageName]] += "window.go." + normalisedPackageNames[packageName] + " = {\n"
for _, structName := range structNames {
result[normalisedPackageNames[packageName]] += " " + structName + ": {\n"
methods := packageBindings[structName]
sort.Slice(methods, func(i, j int) bool {
return methods[i].Name < methods[j].Name
})
for _, method := range methods {
result[normalisedPackageNames[packageName]] += " " + method.Name + ",\n"
}
result[normalisedPackageNames[packageName]] += " },\n"
}
result[normalisedPackageNames[packageName]] += "};\n"
// add imports
if len(allModels) > 0 {
allModels := lo.Uniq(allModels)
var models []string
for _, model := range allModels {
models = append(models, normalisedPackageNames[model])
}
sort.Strings(models)
result[normalisedPackageNames[packageName]] += "\n"
imports := "import {" + strings.Join(models, ", ") + "} from './models';\n"
result[normalisedPackageNames[packageName]] = imports + "\n" + result[normalisedPackageNames[packageName]]
}
result[normalisedPackageNames[packageName]] = header + result[normalisedPackageNames[packageName]]
}
return result
}
+124
View File
@@ -0,0 +1,124 @@
package parser
import (
"embed"
"io/fs"
"os"
"testing"
"github.com/google/go-cmp/cmp"
)
//go:embed testdata
var testdata embed.FS
func getFile(filename string) string {
// get the file from the testdata FS
file, err := fs.ReadFile(testdata, filename)
if err != nil {
panic(err)
}
return string(file)
}
func TestGenerateBindings(t *testing.T) {
tests := []struct {
dir string
want map[string]string
}{
{
"testdata/function_single",
map[string]string{
"main": getFile("testdata/function_single/bindings_main.js"),
},
},
{
"testdata/function_from_imported_package",
map[string]string{
"main": getFile("testdata/function_from_imported_package/bindings_main.js"),
"services": getFile("testdata/function_from_imported_package/bindings_services.js"),
},
},
{
"testdata/variable_single",
map[string]string{
"main": getFile("testdata/variable_single/bindings_main.js"),
},
},
{
"testdata/variable_single_from_function",
map[string]string{
"main": getFile("testdata/variable_single_from_function/bindings_main.js"),
},
},
{
"testdata/variable_single_from_other_function",
map[string]string{
"main": getFile("testdata/variable_single_from_other_function/bindings_main.js"),
"services": getFile("testdata/variable_single_from_other_function/bindings_services.js"),
},
},
{
"testdata/struct_literal_single",
map[string]string{
"main": getFile("testdata/struct_literal_single/bindings_main.js"),
},
},
{
"testdata/struct_literal_multiple",
map[string]string{
"main": getFile("testdata/struct_literal_multiple/bindings_main.js"),
},
},
{
"testdata/struct_literal_multiple_other",
map[string]string{
"main": getFile("testdata/struct_literal_multiple_other/bindings_main.js"),
"services": getFile("testdata/struct_literal_multiple_other/bindings_services.js"),
},
},
{
"testdata/struct_literal_multiple_files",
map[string]string{
"main": getFile("testdata/struct_literal_multiple_files/bindings_main.js"),
},
},
}
for _, tt := range tests {
t.Run(tt.dir, func(t *testing.T) {
// Run parser on directory
project, err := ParseProject(tt.dir)
if err != nil {
t.Errorf("ParseProject() error = %v", err)
return
}
// Generate Bindings
got := GenerateBindings(project.BoundMethods)
for name, binding := range got {
// check if the binding is in the expected bindings
expected, ok := tt.want[name]
if !ok {
err = os.WriteFile(tt.dir+"/bindings_"+name+".got.js", []byte(binding), 0644)
if err != nil {
t.Errorf("os.WriteFile() error = %v", err)
return
}
t.Errorf("GenerateBindings() unexpected binding = %v", name)
return
}
// compare the binding
if diff := cmp.Diff(expected, binding); diff != "" {
err = os.WriteFile(tt.dir+"/bindings_"+name+".got.js", []byte(binding), 0644)
if err != nil {
t.Errorf("os.WriteFile() error = %v", err)
return
}
t.Fatalf("GenerateBindings() mismatch (-want +got):\n%s", diff)
}
}
})
}
}

Some files were not shown because too many files have changed in this diff Show More