5
0
mirror of https://github.com/wailsapp/wails.git synced 2025-05-03 04:11:05 +08:00

Improved bindings generation

This commit is contained in:
Lea Anthony 2022-04-03 07:31:07 +10:00
parent d119fce3c3
commit 4721949657
No known key found for this signature in database
GPG Key ID: 33DAF7BB90A58405
5 changed files with 132 additions and 20 deletions

View File

@ -4,6 +4,9 @@
package appng
import (
"os"
"path/filepath"
"github.com/leaanthony/gosod"
"github.com/wailsapp/wails/v2/internal/binding"
wailsRuntime "github.com/wailsapp/wails/v2/internal/frontend/runtime"
@ -12,8 +15,6 @@ import (
"github.com/wailsapp/wails/v2/internal/logger"
"github.com/wailsapp/wails/v2/internal/project"
"github.com/wailsapp/wails/v2/pkg/options"
"os"
"path/filepath"
)
// App defines a Wails application structure
@ -96,6 +97,10 @@ func generateBindings(bindings *binding.Bindings) error {
return err
}
err = bindings.GenerateGoBindings(targetDir)
if err != nil {
return err
}
// Write backend method wrappers
bindingsFilename := filepath.Join(targetDir, "bindings.js")
err = bindings.GenerateBackendJS(bindingsFilename)

View File

@ -225,6 +225,11 @@ func generateBindings(bindings *binding.Bindings) error {
return err
}
err = bindings.GenerateGoBindings(targetDir)
if err != nil {
return err
}
// Write backend method wrappers
bindingsFilename := filepath.Join(targetDir, "bindings.js")
err = bindings.GenerateBackendJS(bindingsFilename)

View File

@ -14,6 +14,7 @@ type BoundMethod struct {
Outputs []*Parameter `json:"outputs,omitempty"`
Comments string `json:"comments,omitempty"`
Method reflect.Value `json:"-"`
StructNames []string `json:"structNames"`
}
// InputCount returns the number of inputs this bound method has

View File

@ -16,6 +16,83 @@ import (
//go:embed assets/package.json
var packageJSON []byte
func (b *Bindings) GenerateGoBindings(baseDir string) error {
store := b.db.store
for packageName, structs := range store {
packageDir := filepath.Join(baseDir, packageName)
err := fs.Mkdir(packageDir)
if err != nil {
return err
}
for structName, methods := range structs {
var jsoutput bytes.Buffer
jsoutput.WriteString(`// @ts-check
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
`)
var tsoutput bytes.Buffer
tsoutput.WriteString(`// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
`)
for methodName, methodDetails := range methods {
// Generate JS
var args slicer.StringSlicer
for count := range methodDetails.Inputs {
arg := fmt.Sprintf("arg%d", count+1)
args.Add(arg)
}
argsString := args.Join(", ")
jsoutput.WriteString(fmt.Sprintf("\nexport function %s(%s) {", methodName, argsString))
jsoutput.WriteString("\n")
jsoutput.WriteString(fmt.Sprintf(" return window['go']['%s']['%s']['%s'](%s);", packageName, structName, methodName, argsString))
jsoutput.WriteString("\n")
jsoutput.WriteString(fmt.Sprintf("}"))
jsoutput.WriteString("\n")
// Generate TS
if len(methodDetails.StructNames) > 0 {
classes := strings.Join(methodDetails.StructNames, ", ")
tsoutput.WriteString("import {" + classes + "} from '../models';")
}
tsoutput.WriteString(fmt.Sprintf("\nexport function %s(", methodName))
args.Clear()
for count, input := range methodDetails.Inputs {
arg := fmt.Sprintf("arg%d", count+1)
args.Add(arg + ":" + goTypeToTypescriptType(input.TypeName, false))
}
tsoutput.WriteString(args.Join(",") + "):")
returnType := "Promise"
if methodDetails.OutputCount() > 0 {
firstType := goTypeToTypescriptType(methodDetails.Outputs[0].TypeName, false)
returnType += "<" + firstType
if methodDetails.OutputCount() == 2 {
secondType := goTypeToTypescriptType(methodDetails.Outputs[1].TypeName, false)
returnType += "|" + secondType
}
returnType += ">"
} else {
returnType = "Promise<void>"
}
tsoutput.WriteString(returnType + ";\n")
}
jsfilename := filepath.Join(packageDir, structName+".js")
err = os.WriteFile(jsfilename, jsoutput.Bytes(), 0755)
if err != nil {
return err
}
tsfilename := filepath.Join(packageDir, structName+".d.ts")
err = os.WriteFile(tsfilename, tsoutput.Bytes(), 0755)
if err != nil {
return err
}
}
}
return nil
}
func (b *Bindings) GenerateBackendJS(targetfile string) error {
store := b.db.store
@ -24,6 +101,13 @@ func (b *Bindings) GenerateBackendJS(targetfile string) error {
output.WriteString(`// @ts-check
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
// This file is automatically generated. DO NOT EDIT
// ************************************************
// This file is deprecated and will not be generated
// in the next version of Wails. Bindings are now
// generated in their own files.
// ************************************************
`)
output.WriteString(`const go = {`)
@ -63,15 +147,15 @@ func (b *Bindings) GenerateBackendJS(targetfile string) error {
for count, input := range methodDetails.Inputs {
arg := fmt.Sprintf("arg%d", count+1)
args.Add(arg)
output.WriteString(fmt.Sprintf(" * @param {%s} %s - Go Type: %s\n", goTypeToJSDocType(input.TypeName), arg, input.TypeName))
output.WriteString(fmt.Sprintf(" * @param {%s} %s - Go Type: %s\n", goTypeToJSDocType(input.TypeName, true), arg, input.TypeName))
}
returnType := "Promise"
returnTypeDetails := ""
if methodDetails.OutputCount() > 0 {
firstType := goTypeToJSDocType(methodDetails.Outputs[0].TypeName)
firstType := goTypeToJSDocType(methodDetails.Outputs[0].TypeName, true)
returnType += "<" + firstType
if methodDetails.OutputCount() == 2 {
secondType := goTypeToJSDocType(methodDetails.Outputs[1].TypeName)
secondType := goTypeToJSDocType(methodDetails.Outputs[1].TypeName, true)
returnType += "|" + secondType
}
returnType += ">"
@ -120,6 +204,16 @@ func (b *Bindings) GenerateBackendTS(targetfile string) error {
store := b.db.store
var output bytes.Buffer
output.WriteString(`
// ************************************************
// This file is deprecated and will not be generated
// in the next version of Wails. Bindings are now
// generated in their own files.
// ************************************************
`)
output.WriteString("import * as models from './models';\n\n")
output.WriteString("export interface go {\n")
@ -140,7 +234,7 @@ func (b *Bindings) GenerateBackendTS(targetfile string) error {
sortedStructNames.Each(func(structName string) {
structs := packages[structName]
output.WriteString(fmt.Sprintf(" \"models.%s\": {", structName))
output.WriteString(fmt.Sprintf(" \"%s\": {", structName))
output.WriteString("\n")
var sortedMethodNames slicer.StringSlicer
@ -156,15 +250,15 @@ func (b *Bindings) GenerateBackendTS(targetfile string) error {
var args slicer.StringSlicer
for count, input := range methodDetails.Inputs {
arg := fmt.Sprintf("arg%d", count+1)
args.Add(arg + ":" + goTypeToTypescriptType(input.TypeName))
args.Add(arg + ":" + goTypeToTypescriptType(input.TypeName, true))
}
output.WriteString(args.Join(",") + "):")
returnType := "Promise"
if methodDetails.OutputCount() > 0 {
firstType := goTypeToTypescriptType(methodDetails.Outputs[0].TypeName)
firstType := goTypeToTypescriptType(methodDetails.Outputs[0].TypeName, true)
returnType += "<" + firstType
if methodDetails.OutputCount() == 2 {
secondType := goTypeToTypescriptType(methodDetails.Outputs[1].TypeName)
secondType := goTypeToTypescriptType(methodDetails.Outputs[1].TypeName, true)
returnType += "|" + secondType
}
returnType += ">"
@ -191,7 +285,7 @@ declare global {
return os.WriteFile(targetfile, output.Bytes(), 0755)
}
func goTypeToJSDocType(input string) string {
func goTypeToJSDocType(input string, useModelsNamespace bool) string {
switch true {
case input == "interface{}":
return "any"
@ -209,20 +303,23 @@ func goTypeToJSDocType(input string) string {
case input == "[]byte":
return "string"
case strings.HasPrefix(input, "[]"):
arrayType := goTypeToJSDocType(input[2:])
arrayType := goTypeToJSDocType(input[2:], useModelsNamespace)
return "Array<" + arrayType + ">"
default:
if strings.ContainsRune(input, '.') {
if useModelsNamespace {
return "models." + strings.Split(input, ".")[1]
}
return strings.Split(input, ".")[1]
}
return "any"
}
}
func goTypeToTypescriptType(input string) string {
func goTypeToTypescriptType(input string, useModelsNamespace bool) string {
if strings.HasPrefix(input, "[]") {
arrayType := goTypeToJSDocType(input[2:])
arrayType := goTypeToJSDocType(input[2:], useModelsNamespace)
return "Array<" + arrayType + ">"
}
return goTypeToJSDocType(input)
return goTypeToJSDocType(input, useModelsNamespace)
}

View File

@ -91,6 +91,7 @@ func (b *Bindings) getMethods(value interface{}) ([]*BoundMethod, error) {
a := reflect.New(typ)
s := reflect.Indirect(a).Interface()
b.converter.Add(s)
boundMethod.StructNames = append(boundMethod.StructNames, thisInput.Name())
}
}
@ -99,6 +100,7 @@ func (b *Bindings) getMethods(value interface{}) ([]*BoundMethod, error) {
a := reflect.New(thisInput)
s := reflect.Indirect(a).Interface()
b.converter.Add(s)
boundMethod.StructNames = append(boundMethod.StructNames, thisInput.Name())
}
inputs = append(inputs, thisParam)
@ -128,6 +130,7 @@ func (b *Bindings) getMethods(value interface{}) ([]*BoundMethod, error) {
a := reflect.New(typ)
s := reflect.Indirect(a).Interface()
b.converter.Add(s)
boundMethod.StructNames = append(boundMethod.StructNames, thisOutput.Name())
}
}
@ -136,6 +139,7 @@ func (b *Bindings) getMethods(value interface{}) ([]*BoundMethod, error) {
a := reflect.New(thisOutput)
s := reflect.Indirect(a).Interface()
b.converter.Add(s)
boundMethod.StructNames = append(boundMethod.StructNames, thisOutput.Name())
}
outputs = append(outputs, thisParam)