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:
parent
d119fce3c3
commit
4721949657
@ -4,6 +4,9 @@
|
|||||||
package appng
|
package appng
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/leaanthony/gosod"
|
"github.com/leaanthony/gosod"
|
||||||
"github.com/wailsapp/wails/v2/internal/binding"
|
"github.com/wailsapp/wails/v2/internal/binding"
|
||||||
wailsRuntime "github.com/wailsapp/wails/v2/internal/frontend/runtime"
|
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/logger"
|
||||||
"github.com/wailsapp/wails/v2/internal/project"
|
"github.com/wailsapp/wails/v2/internal/project"
|
||||||
"github.com/wailsapp/wails/v2/pkg/options"
|
"github.com/wailsapp/wails/v2/pkg/options"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// App defines a Wails application structure
|
// App defines a Wails application structure
|
||||||
@ -96,6 +97,10 @@ func generateBindings(bindings *binding.Bindings) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = bindings.GenerateGoBindings(targetDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
// Write backend method wrappers
|
// Write backend method wrappers
|
||||||
bindingsFilename := filepath.Join(targetDir, "bindings.js")
|
bindingsFilename := filepath.Join(targetDir, "bindings.js")
|
||||||
err = bindings.GenerateBackendJS(bindingsFilename)
|
err = bindings.GenerateBackendJS(bindingsFilename)
|
||||||
|
@ -225,6 +225,11 @@ func generateBindings(bindings *binding.Bindings) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = bindings.GenerateGoBindings(targetDir)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Write backend method wrappers
|
// Write backend method wrappers
|
||||||
bindingsFilename := filepath.Join(targetDir, "bindings.js")
|
bindingsFilename := filepath.Join(targetDir, "bindings.js")
|
||||||
err = bindings.GenerateBackendJS(bindingsFilename)
|
err = bindings.GenerateBackendJS(bindingsFilename)
|
||||||
|
@ -9,11 +9,12 @@ import (
|
|||||||
// BoundMethod defines all the data related to a Go method that is
|
// BoundMethod defines all the data related to a Go method that is
|
||||||
// bound to the Wails application
|
// bound to the Wails application
|
||||||
type BoundMethod struct {
|
type BoundMethod struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Inputs []*Parameter `json:"inputs,omitempty"`
|
Inputs []*Parameter `json:"inputs,omitempty"`
|
||||||
Outputs []*Parameter `json:"outputs,omitempty"`
|
Outputs []*Parameter `json:"outputs,omitempty"`
|
||||||
Comments string `json:"comments,omitempty"`
|
Comments string `json:"comments,omitempty"`
|
||||||
Method reflect.Value `json:"-"`
|
Method reflect.Value `json:"-"`
|
||||||
|
StructNames []string `json:"structNames"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// InputCount returns the number of inputs this bound method has
|
// InputCount returns the number of inputs this bound method has
|
||||||
|
@ -16,6 +16,83 @@ import (
|
|||||||
//go:embed assets/package.json
|
//go:embed assets/package.json
|
||||||
var packageJSON []byte
|
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 {
|
func (b *Bindings) GenerateBackendJS(targetfile string) error {
|
||||||
|
|
||||||
store := b.db.store
|
store := b.db.store
|
||||||
@ -24,6 +101,13 @@ func (b *Bindings) GenerateBackendJS(targetfile string) error {
|
|||||||
output.WriteString(`// @ts-check
|
output.WriteString(`// @ts-check
|
||||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||||
// This file is automatically generated. DO NOT EDIT
|
// 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 = {`)
|
output.WriteString(`const go = {`)
|
||||||
@ -63,15 +147,15 @@ func (b *Bindings) GenerateBackendJS(targetfile string) error {
|
|||||||
for count, input := range methodDetails.Inputs {
|
for count, input := range methodDetails.Inputs {
|
||||||
arg := fmt.Sprintf("arg%d", count+1)
|
arg := fmt.Sprintf("arg%d", count+1)
|
||||||
args.Add(arg)
|
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"
|
returnType := "Promise"
|
||||||
returnTypeDetails := ""
|
returnTypeDetails := ""
|
||||||
if methodDetails.OutputCount() > 0 {
|
if methodDetails.OutputCount() > 0 {
|
||||||
firstType := goTypeToJSDocType(methodDetails.Outputs[0].TypeName)
|
firstType := goTypeToJSDocType(methodDetails.Outputs[0].TypeName, true)
|
||||||
returnType += "<" + firstType
|
returnType += "<" + firstType
|
||||||
if methodDetails.OutputCount() == 2 {
|
if methodDetails.OutputCount() == 2 {
|
||||||
secondType := goTypeToJSDocType(methodDetails.Outputs[1].TypeName)
|
secondType := goTypeToJSDocType(methodDetails.Outputs[1].TypeName, true)
|
||||||
returnType += "|" + secondType
|
returnType += "|" + secondType
|
||||||
}
|
}
|
||||||
returnType += ">"
|
returnType += ">"
|
||||||
@ -120,6 +204,16 @@ func (b *Bindings) GenerateBackendTS(targetfile string) error {
|
|||||||
store := b.db.store
|
store := b.db.store
|
||||||
var output bytes.Buffer
|
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("import * as models from './models';\n\n")
|
||||||
output.WriteString("export interface go {\n")
|
output.WriteString("export interface go {\n")
|
||||||
|
|
||||||
@ -140,7 +234,7 @@ func (b *Bindings) GenerateBackendTS(targetfile string) error {
|
|||||||
|
|
||||||
sortedStructNames.Each(func(structName string) {
|
sortedStructNames.Each(func(structName string) {
|
||||||
structs := packages[structName]
|
structs := packages[structName]
|
||||||
output.WriteString(fmt.Sprintf(" \"models.%s\": {", structName))
|
output.WriteString(fmt.Sprintf(" \"%s\": {", structName))
|
||||||
output.WriteString("\n")
|
output.WriteString("\n")
|
||||||
|
|
||||||
var sortedMethodNames slicer.StringSlicer
|
var sortedMethodNames slicer.StringSlicer
|
||||||
@ -156,15 +250,15 @@ func (b *Bindings) GenerateBackendTS(targetfile string) error {
|
|||||||
var args slicer.StringSlicer
|
var args slicer.StringSlicer
|
||||||
for count, input := range methodDetails.Inputs {
|
for count, input := range methodDetails.Inputs {
|
||||||
arg := fmt.Sprintf("arg%d", count+1)
|
arg := fmt.Sprintf("arg%d", count+1)
|
||||||
args.Add(arg + ":" + goTypeToTypescriptType(input.TypeName))
|
args.Add(arg + ":" + goTypeToTypescriptType(input.TypeName, true))
|
||||||
}
|
}
|
||||||
output.WriteString(args.Join(",") + "):")
|
output.WriteString(args.Join(",") + "):")
|
||||||
returnType := "Promise"
|
returnType := "Promise"
|
||||||
if methodDetails.OutputCount() > 0 {
|
if methodDetails.OutputCount() > 0 {
|
||||||
firstType := goTypeToTypescriptType(methodDetails.Outputs[0].TypeName)
|
firstType := goTypeToTypescriptType(methodDetails.Outputs[0].TypeName, true)
|
||||||
returnType += "<" + firstType
|
returnType += "<" + firstType
|
||||||
if methodDetails.OutputCount() == 2 {
|
if methodDetails.OutputCount() == 2 {
|
||||||
secondType := goTypeToTypescriptType(methodDetails.Outputs[1].TypeName)
|
secondType := goTypeToTypescriptType(methodDetails.Outputs[1].TypeName, true)
|
||||||
returnType += "|" + secondType
|
returnType += "|" + secondType
|
||||||
}
|
}
|
||||||
returnType += ">"
|
returnType += ">"
|
||||||
@ -191,7 +285,7 @@ declare global {
|
|||||||
return os.WriteFile(targetfile, output.Bytes(), 0755)
|
return os.WriteFile(targetfile, output.Bytes(), 0755)
|
||||||
}
|
}
|
||||||
|
|
||||||
func goTypeToJSDocType(input string) string {
|
func goTypeToJSDocType(input string, useModelsNamespace bool) string {
|
||||||
switch true {
|
switch true {
|
||||||
case input == "interface{}":
|
case input == "interface{}":
|
||||||
return "any"
|
return "any"
|
||||||
@ -209,20 +303,23 @@ func goTypeToJSDocType(input string) string {
|
|||||||
case input == "[]byte":
|
case input == "[]byte":
|
||||||
return "string"
|
return "string"
|
||||||
case strings.HasPrefix(input, "[]"):
|
case strings.HasPrefix(input, "[]"):
|
||||||
arrayType := goTypeToJSDocType(input[2:])
|
arrayType := goTypeToJSDocType(input[2:], useModelsNamespace)
|
||||||
return "Array<" + arrayType + ">"
|
return "Array<" + arrayType + ">"
|
||||||
default:
|
default:
|
||||||
if strings.ContainsRune(input, '.') {
|
if strings.ContainsRune(input, '.') {
|
||||||
return "models." + strings.Split(input, ".")[1]
|
if useModelsNamespace {
|
||||||
|
return "models." + strings.Split(input, ".")[1]
|
||||||
|
}
|
||||||
|
return strings.Split(input, ".")[1]
|
||||||
}
|
}
|
||||||
return "any"
|
return "any"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func goTypeToTypescriptType(input string) string {
|
func goTypeToTypescriptType(input string, useModelsNamespace bool) string {
|
||||||
if strings.HasPrefix(input, "[]") {
|
if strings.HasPrefix(input, "[]") {
|
||||||
arrayType := goTypeToJSDocType(input[2:])
|
arrayType := goTypeToJSDocType(input[2:], useModelsNamespace)
|
||||||
return "Array<" + arrayType + ">"
|
return "Array<" + arrayType + ">"
|
||||||
}
|
}
|
||||||
return goTypeToJSDocType(input)
|
return goTypeToJSDocType(input, useModelsNamespace)
|
||||||
}
|
}
|
||||||
|
@ -91,6 +91,7 @@ func (b *Bindings) getMethods(value interface{}) ([]*BoundMethod, error) {
|
|||||||
a := reflect.New(typ)
|
a := reflect.New(typ)
|
||||||
s := reflect.Indirect(a).Interface()
|
s := reflect.Indirect(a).Interface()
|
||||||
b.converter.Add(s)
|
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)
|
a := reflect.New(thisInput)
|
||||||
s := reflect.Indirect(a).Interface()
|
s := reflect.Indirect(a).Interface()
|
||||||
b.converter.Add(s)
|
b.converter.Add(s)
|
||||||
|
boundMethod.StructNames = append(boundMethod.StructNames, thisInput.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
inputs = append(inputs, thisParam)
|
inputs = append(inputs, thisParam)
|
||||||
@ -128,6 +130,7 @@ func (b *Bindings) getMethods(value interface{}) ([]*BoundMethod, error) {
|
|||||||
a := reflect.New(typ)
|
a := reflect.New(typ)
|
||||||
s := reflect.Indirect(a).Interface()
|
s := reflect.Indirect(a).Interface()
|
||||||
b.converter.Add(s)
|
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)
|
a := reflect.New(thisOutput)
|
||||||
s := reflect.Indirect(a).Interface()
|
s := reflect.Indirect(a).Interface()
|
||||||
b.converter.Add(s)
|
b.converter.Add(s)
|
||||||
|
boundMethod.StructNames = append(boundMethod.StructNames, thisOutput.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
outputs = append(outputs, thisParam)
|
outputs = append(outputs, thisParam)
|
||||||
|
Loading…
Reference in New Issue
Block a user