mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-02 19:50:15 +08:00
Initial bindings.js generation
This commit is contained in:
parent
868b769e7f
commit
71aa7c9731
@ -2,6 +2,8 @@ package parser
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/samber/lo"
|
||||||
)
|
)
|
||||||
|
|
||||||
const helperTemplate = `function {{structName}}(method) {
|
const helperTemplate = `function {{structName}}(method) {
|
||||||
@ -11,7 +13,8 @@ const helperTemplate = `function {{structName}}(method) {
|
|||||||
methodName: method,
|
methodName: method,
|
||||||
args: Array.prototype.slice.call(arguments, 1),
|
args: Array.prototype.slice.call(arguments, 1),
|
||||||
};
|
};
|
||||||
}`
|
}
|
||||||
|
`
|
||||||
|
|
||||||
func GenerateHelper(packageName, structName string) string {
|
func GenerateHelper(packageName, structName string) string {
|
||||||
result := strings.ReplaceAll(helperTemplate, "{{packageName}}", packageName)
|
result := strings.ReplaceAll(helperTemplate, "{{packageName}}", packageName)
|
||||||
@ -20,45 +23,109 @@ func GenerateHelper(packageName, structName string) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const bindingTemplate = `
|
const bindingTemplate = `
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {{structName}}.{{methodName}}
|
* {{structName}}.{{methodName}}
|
||||||
* Comments
|
* Comments
|
||||||
* @param name {string}
|
* @param name {string}
|
||||||
* @returns {Promise<string>}
|
* @returns {Promise<string>}
|
||||||
*/
|
**/
|
||||||
function {{methodName}}({{args}}) {
|
function {{methodName}}({{inputs}}) {
|
||||||
return wails.Call({{structName}}("{{methodName}}", {{args}}));
|
return wails.Call({{structName}}("{{methodName}}"{{args}}));
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
func GenerateBinding(structName string, method *BoundMethod) string {
|
func sanitiseJSVarName(name string) string {
|
||||||
|
// if the name is a reserved word, prefix with an
|
||||||
|
// underscore
|
||||||
|
if strings.Contains("break,case,catch,class,const,continue,debugger,default,delete,do,else,enum,export,extends,false,finally,for,function,if,implements,import,in,instanceof,interface,let,new,null,package,private,protected,public,return,static,super,switch,this,throw,true,try,typeof,var,void,while,with,yield", 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(bindingTemplate, "{{structName}}", structName)
|
||||||
result = strings.ReplaceAll(result, "{{methodName}}", method.Name)
|
result = strings.ReplaceAll(result, "{{methodName}}", method.Name)
|
||||||
result = strings.ReplaceAll(result, "Comments", strings.TrimSpace(method.DocComment))
|
comments := strings.TrimSpace(method.DocComment)
|
||||||
|
result = strings.ReplaceAll(result, "Comments", comments)
|
||||||
var params string
|
var params string
|
||||||
for _, input := range method.Inputs {
|
for _, input := range method.Inputs {
|
||||||
params += " * @param " + input.Name + " {" + input.JSType() + "}\n"
|
pkgName := getPackageName(input)
|
||||||
|
if pkgName != "" {
|
||||||
|
models = append(models, pkgName)
|
||||||
|
}
|
||||||
|
params += " * @param " + sanitiseJSVarName(input.Name) + " {" + input.JSType() + "}\n"
|
||||||
}
|
}
|
||||||
params = strings.TrimSuffix(params, "\n")
|
params = strings.TrimSuffix(params, "\n")
|
||||||
result = strings.ReplaceAll(result, " * @param name {string}", params)
|
if len(params) == 0 {
|
||||||
var args string
|
params = " *"
|
||||||
for _, input := range method.Inputs {
|
|
||||||
args += input.Name + ", "
|
|
||||||
}
|
}
|
||||||
args = strings.TrimSuffix(args, ", ")
|
////params += "\n"
|
||||||
|
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)
|
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
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateBindings(bindings map[string]map[string][]*BoundMethod) string {
|
func GenerateBindings(bindings map[string]map[string][]*BoundMethod) string {
|
||||||
|
|
||||||
var result string
|
var result string
|
||||||
|
var allModels []string
|
||||||
for packageName, packageBindings := range bindings {
|
for packageName, packageBindings := range bindings {
|
||||||
for structName, bindings := range packageBindings {
|
for structName, bindings := range packageBindings {
|
||||||
result += GenerateHelper(packageName, structName)
|
result += GenerateHelper(packageName, structName)
|
||||||
for _, binding := range bindings {
|
for _, binding := range bindings {
|
||||||
result += GenerateBinding(structName, binding)
|
thisBinding, models := GenerateBinding(structName, binding)
|
||||||
|
result += thisBinding
|
||||||
|
allModels = append(allModels, models...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -76,5 +143,10 @@ window.go = window.go || {};
|
|||||||
}
|
}
|
||||||
result += "};\n"
|
result += "};\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add imports
|
||||||
|
imports := "import {" + strings.Join(lo.Uniq(allModels), ", ") + "} from './models';\n"
|
||||||
|
result = imports + "\n" + result
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -1,66 +1,46 @@
|
|||||||
package parser
|
package parser
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/google/go-cmp/cmp"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
)
|
)
|
||||||
|
|
||||||
const expectedGreetService = `function GreetService(method) {
|
func TestGenerateBindings(t *testing.T) {
|
||||||
return {
|
|
||||||
packageName: "main",
|
|
||||||
serviceName: "GreetService",
|
|
||||||
methodName: method,
|
|
||||||
args: Array.prototype.slice.call(arguments, 1),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
tests := []string{
|
||||||
* GreetService.Greet
|
"struct_literal_single",
|
||||||
* Greet someone
|
|
||||||
* @param name {string}
|
|
||||||
* @returns {Promise<string>}
|
|
||||||
*/
|
|
||||||
function Greet(name) {
|
|
||||||
return wails.Call(GreetService("Greet", name));
|
|
||||||
}
|
|
||||||
|
|
||||||
window.go = window.go || {};
|
|
||||||
Object.window.go.main = {
|
|
||||||
GreetService: {
|
|
||||||
Greet,
|
|
||||||
}
|
|
||||||
};
|
|
||||||
`
|
|
||||||
|
|
||||||
func TestGenerateGreetService(t *testing.T) {
|
|
||||||
parsedMethods := map[string]map[string][]*BoundMethod{
|
|
||||||
"main": {
|
|
||||||
"GreetService": {
|
|
||||||
{
|
|
||||||
Name: "Greet",
|
|
||||||
DocComment: "Greet someone\n",
|
|
||||||
Inputs: []*Parameter{
|
|
||||||
{
|
|
||||||
Name: "name",
|
|
||||||
Type: &ParameterType{
|
|
||||||
Name: "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Outputs: []*Parameter{
|
|
||||||
{
|
|
||||||
Name: "",
|
|
||||||
Type: &ParameterType{
|
|
||||||
Name: "string",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
got := GenerateBindings(parsedMethods)
|
for _, projectDir := range tests {
|
||||||
if diff := cmp.Diff(expectedGreetService, got); diff != "" {
|
t.Run(projectDir, func(t *testing.T) {
|
||||||
t.Fatalf("GenerateService() mismatch (-want +got):\n%s", diff)
|
projectDir = "testdata/" + projectDir
|
||||||
|
// Run parser on directory
|
||||||
|
project, err := ParseProject(projectDir)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("ParseProject() error = %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate Bindings
|
||||||
|
got := GenerateBindings(project.BoundMethods)
|
||||||
|
// Write file to project directory
|
||||||
|
err = os.WriteFile(projectDir+"/bindings.got.js", []byte(got), 0644)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("os.WriteFile() error = %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Load bindings.js from project directory
|
||||||
|
expected, err := os.ReadFile(projectDir + "/bindings.js")
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("os.ReadFile() error = %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare
|
||||||
|
if diff := cmp.Diff(string(expected), got); diff != "" {
|
||||||
|
t.Fatalf("GenerateService() mismatch (-want +got):\n%s", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ func (p *Parameter) JSType() string {
|
|||||||
// Convert type to javascript equivalent type
|
// Convert type to javascript equivalent type
|
||||||
var typeName string
|
var typeName string
|
||||||
switch p.Type.Name {
|
switch p.Type.Name {
|
||||||
case "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64", "uintptr":
|
case "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64", "uintptr", "float32", "float64":
|
||||||
typeName = "number"
|
typeName = "number"
|
||||||
case "string":
|
case "string":
|
||||||
typeName = "string"
|
typeName = "string"
|
||||||
|
Loading…
Reference in New Issue
Block a user