mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-02 04:40:41 +08:00

* Do not attempt to export fields that cannot be json-encoded * update changelog w/ PR * also skip UnsafePointers * WIP to allow conversion from Go generic types to typescript * support for non-primitive generics also :) * fix generic types in parameters / return args * fixes a namespacing bug when mapping to pointer to struct * fixing invalid knownstructs * found a place it mattered, pushing the star replacement to the generate side * descend as much as necessary to find structs caught these examples in http.Request.TLS: PeerCertificates []*x509.Certificate VerifiedChains [][]*x509.Certificate * accidently reverted other fix * switch syntax for typescript record outputs prior syntax is primarily useful for naming keys so not useful here, and this syntax avoids square brackets in output which greatly simplifies generation for Go generics * better handle edge cases for nested arrays and slices * lots o tests * update changelog --------- Co-authored-by: Lea Anthony <lea.anthony@gmail.com>
177 lines
4.7 KiB
Go
177 lines
4.7 KiB
Go
package binding
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"runtime"
|
|
"strings"
|
|
)
|
|
|
|
// isStructPtr returns true if the value given is a
|
|
// pointer to a struct
|
|
func isStructPtr(value interface{}) bool {
|
|
return reflect.ValueOf(value).Kind() == reflect.Ptr &&
|
|
reflect.ValueOf(value).Elem().Kind() == reflect.Struct
|
|
}
|
|
|
|
// isFunction returns true if the given value is a function
|
|
func isFunction(value interface{}) bool {
|
|
return reflect.ValueOf(value).Kind() == reflect.Func
|
|
}
|
|
|
|
// isStruct returns true if the value given is a struct
|
|
func isStruct(value interface{}) bool {
|
|
return reflect.ValueOf(value).Kind() == reflect.Struct
|
|
}
|
|
|
|
func (b *Bindings) getMethods(value interface{}) ([]*BoundMethod, error) {
|
|
// Create result placeholder
|
|
var result []*BoundMethod
|
|
|
|
// Check type
|
|
if !isStructPtr(value) {
|
|
|
|
if isStruct(value) {
|
|
name := reflect.ValueOf(value).Type().Name()
|
|
return nil, fmt.Errorf("%s is a struct, not a pointer to a struct", name)
|
|
}
|
|
|
|
if isFunction(value) {
|
|
name := runtime.FuncForPC(reflect.ValueOf(value).Pointer()).Name()
|
|
return nil, fmt.Errorf("%s is a function, not a pointer to a struct. Wails v2 has deprecated the binding of functions. Please wrap your functions up in a struct and bind a pointer to that struct.", name)
|
|
}
|
|
|
|
return nil, fmt.Errorf("not a pointer to a struct.")
|
|
}
|
|
|
|
// Process Struct
|
|
structType := reflect.TypeOf(value)
|
|
structValue := reflect.ValueOf(value)
|
|
structTypeString := structType.String()
|
|
baseName := structTypeString[1:]
|
|
|
|
// Process Methods
|
|
for i := 0; i < structType.NumMethod(); i++ {
|
|
methodDef := structType.Method(i)
|
|
methodName := methodDef.Name
|
|
fullMethodName := baseName + "." + methodName
|
|
method := structValue.MethodByName(methodName)
|
|
|
|
methodReflectName := runtime.FuncForPC(methodDef.Func.Pointer()).Name()
|
|
if b.exemptions.Contains(methodReflectName) {
|
|
continue
|
|
}
|
|
|
|
// Create new method
|
|
boundMethod := &BoundMethod{
|
|
Name: fullMethodName,
|
|
Inputs: nil,
|
|
Outputs: nil,
|
|
Comments: "",
|
|
Method: method,
|
|
}
|
|
|
|
// Iterate inputs
|
|
methodType := method.Type()
|
|
inputParamCount := methodType.NumIn()
|
|
var inputs []*Parameter
|
|
for inputIndex := 0; inputIndex < inputParamCount; inputIndex++ {
|
|
input := methodType.In(inputIndex)
|
|
thisParam := newParameter("", input)
|
|
|
|
thisInput := input
|
|
|
|
if thisInput.Kind() == reflect.Slice {
|
|
thisInput = thisInput.Elem()
|
|
}
|
|
|
|
// Process struct pointer params
|
|
if thisInput.Kind() == reflect.Ptr {
|
|
if thisInput.Elem().Kind() == reflect.Struct {
|
|
typ := thisInput.Elem()
|
|
a := reflect.New(typ)
|
|
s := reflect.Indirect(a).Interface()
|
|
name := typ.Name()
|
|
packageName := getPackageName(thisInput.String())
|
|
b.AddStructToGenerateTS(packageName, name, s)
|
|
}
|
|
}
|
|
|
|
// Process struct params
|
|
if thisInput.Kind() == reflect.Struct {
|
|
a := reflect.New(thisInput)
|
|
s := reflect.Indirect(a).Interface()
|
|
name := thisInput.Name()
|
|
packageName := getPackageName(thisInput.String())
|
|
b.AddStructToGenerateTS(packageName, name, s)
|
|
}
|
|
|
|
inputs = append(inputs, thisParam)
|
|
}
|
|
|
|
boundMethod.Inputs = inputs
|
|
|
|
// Iterate outputs
|
|
// TODO: Determine what to do about limiting return types
|
|
// especially around errors.
|
|
outputParamCount := methodType.NumOut()
|
|
var outputs []*Parameter
|
|
for outputIndex := 0; outputIndex < outputParamCount; outputIndex++ {
|
|
output := methodType.Out(outputIndex)
|
|
thisParam := newParameter("", output)
|
|
|
|
thisOutput := output
|
|
|
|
if thisOutput.Kind() == reflect.Slice {
|
|
thisOutput = thisOutput.Elem()
|
|
}
|
|
|
|
// Process struct pointer params
|
|
if thisOutput.Kind() == reflect.Ptr {
|
|
if thisOutput.Elem().Kind() == reflect.Struct {
|
|
typ := thisOutput.Elem()
|
|
a := reflect.New(typ)
|
|
s := reflect.Indirect(a).Interface()
|
|
name := typ.Name()
|
|
packageName := getPackageName(thisOutput.String())
|
|
b.AddStructToGenerateTS(packageName, name, s)
|
|
}
|
|
}
|
|
|
|
// Process struct params
|
|
if thisOutput.Kind() == reflect.Struct {
|
|
a := reflect.New(thisOutput)
|
|
s := reflect.Indirect(a).Interface()
|
|
name := thisOutput.Name()
|
|
packageName := getPackageName(thisOutput.String())
|
|
b.AddStructToGenerateTS(packageName, name, s)
|
|
}
|
|
|
|
outputs = append(outputs, thisParam)
|
|
}
|
|
boundMethod.Outputs = outputs
|
|
|
|
// Save method in result
|
|
result = append(result, boundMethod)
|
|
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func getPackageName(in string) string {
|
|
result := strings.Split(in, ".")[0]
|
|
result = strings.ReplaceAll(result, "[]", "")
|
|
result = strings.ReplaceAll(result, "*", "")
|
|
return result
|
|
}
|
|
|
|
func getSplitReturn(in string) (string, string) {
|
|
result := strings.SplitN(in, ".", 2)
|
|
return result[0], result[1]
|
|
}
|
|
|
|
func hasElements(typ reflect.Type) bool {
|
|
kind := typ.Kind()
|
|
return kind == reflect.Ptr || kind == reflect.Array || kind == reflect.Slice || kind == reflect.Map
|
|
}
|