From 4b04c10f14b4b4e150129007af4b8ef6949b6097 Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Tue, 12 Dec 2023 21:51:40 +1100 Subject: [PATCH] Support bindings, model & enum generation --- v3/internal/commands/bindings.go | 17 +- v3/internal/flags/bindings.go | 11 + v3/internal/parser/README.md | 3 + v3/internal/parser/bindings.go | 39 +- v3/internal/parser/bindings_test.go | 6 + v3/internal/parser/models.go | 135 +- v3/internal/parser/models_test.go | 38 +- v3/internal/parser/parser.go | 265 +- v3/internal/parser/parser_enum_test.go | 162 ++ v3/internal/parser/parser_function_test.go | 204 ++ .../parser_struct_literal_multiple_test.go | 250 ++ ..._struct_literal_non_pointer_single_test.go | 1091 +++++++ .../parser_struct_literal_single_test.go | 1092 +++++++ v3/internal/parser/parser_test.go | 2577 ----------------- .../parser/parser_variable_single_test.go | 238 ++ v3/internal/parser/templates/class.ts.tmpl | 16 - .../parser/templates/interfaces.ts.tmpl | 8 + v3/internal/parser/templates/model.ts.tmpl | 46 +- .../parser/testdata/enum/bindings_main.js | 29 + v3/internal/parser/testdata/enum/main.go | 58 + v3/internal/parser/testdata/enum/models.ts | 33 + .../bindings_main.js | 30 + .../bindings_services.js | 22 + .../enum_from_imported_package/main.go | 37 + .../enum_from_imported_package/models.ts | 47 + .../services/other.go | 16 + .../bindings_main.js | 11 +- .../bindings_services.js | 9 +- .../function_from_imported_package/models.ts | 69 +- .../testdata/function_single/bindings_main.js | 9 +- .../struct_literal_multiple/bindings_main.js | 16 +- .../bindings_main.js | 16 +- .../bindings_main.js | 11 +- .../bindings_services.js | 9 +- .../struct_literal_multiple_other/models.ts | 69 +- .../struct_literal_single/bindings_main.js | 93 +- .../testdata/struct_literal_single/models.ts | 95 +- .../testdata/variable_single/bindings_main.js | 9 +- .../bindings_main.js | 9 +- .../bindings_main.js | 11 +- .../bindings_services.js | 9 +- .../models.ts | 69 +- .../templates/_common/Taskfile.tmpl.yml | 8 +- v3/internal/templates/templates_test.go | 44 - 44 files changed, 3910 insertions(+), 3126 deletions(-) create mode 100644 v3/internal/flags/bindings.go create mode 100644 v3/internal/parser/parser_enum_test.go create mode 100644 v3/internal/parser/parser_function_test.go create mode 100644 v3/internal/parser/parser_struct_literal_multiple_test.go create mode 100644 v3/internal/parser/parser_struct_literal_non_pointer_single_test.go create mode 100644 v3/internal/parser/parser_struct_literal_single_test.go delete mode 100644 v3/internal/parser/parser_test.go create mode 100644 v3/internal/parser/parser_variable_single_test.go delete mode 100644 v3/internal/parser/templates/class.ts.tmpl create mode 100644 v3/internal/parser/templates/interfaces.ts.tmpl create mode 100644 v3/internal/parser/testdata/enum/bindings_main.js create mode 100644 v3/internal/parser/testdata/enum/main.go create mode 100644 v3/internal/parser/testdata/enum/models.ts create mode 100644 v3/internal/parser/testdata/enum_from_imported_package/bindings_main.js create mode 100644 v3/internal/parser/testdata/enum_from_imported_package/bindings_services.js create mode 100644 v3/internal/parser/testdata/enum_from_imported_package/main.go create mode 100644 v3/internal/parser/testdata/enum_from_imported_package/models.ts create mode 100644 v3/internal/parser/testdata/enum_from_imported_package/services/other.go delete mode 100644 v3/internal/templates/templates_test.go diff --git a/v3/internal/commands/bindings.go b/v3/internal/commands/bindings.go index 05d031ef..eaf8b03d 100644 --- a/v3/internal/commands/bindings.go +++ b/v3/internal/commands/bindings.go @@ -1,15 +1,10 @@ package commands -import "github.com/wailsapp/wails/v3/internal/parser" +import ( + "github.com/wailsapp/wails/v3/internal/flags" + "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:"p" description:"The project directory" default:"."` - OutputDirectory string `name:"d" description:"The output directory" default:"."` -} - -func GenerateBindings(options *GenerateBindingsOptions) error { - return parser.GenerateBindingsAndModels(options.ProjectDirectory, options.OutputDirectory) +func GenerateBindings(options *flags.GenerateBindingsOptions) error { + return parser.GenerateBindingsAndModels(options) } diff --git a/v3/internal/flags/bindings.go b/v3/internal/flags/bindings.go new file mode 100644 index 00000000..066ebcd9 --- /dev/null +++ b/v3/internal/flags/bindings.go @@ -0,0 +1,11 @@ +package flags + +type GenerateBindingsOptions struct { + Silent bool `name:"silent" description:"Silent mode"` + ModelsFilename string `name:"m" description:"The filename for the models file" default:"models.ts"` + TSPrefix string `description:"The prefix for the typescript names" default:""` + TSSuffix string `description:"The postfix for the typescript names" default:""` + UseInterfaces bool `name:"i" description:"Use interfaces instead of classes"` + ProjectDirectory string `name:"p" description:"The project directory" default:"."` + OutputDirectory string `name:"d" description:"The output directory" default:"frontend/bindings"` +} diff --git a/v3/internal/parser/README.md b/v3/internal/parser/README.md index fc6a1c70..a9a67ad4 100644 --- a/v3/internal/parser/README.md +++ b/v3/internal/parser/README.md @@ -58,6 +58,9 @@ This package contains the static analyser used for parsing Wails projects so tha - [ ] Maps - [x] Structs - [ ] Generation of bindings + - [ ] Classes + - [ ] Interfaces + - [ ] Enums ## Limitations diff --git a/v3/internal/parser/bindings.go b/v3/internal/parser/bindings.go index c3c23846..7390c668 100644 --- a/v3/internal/parser/bindings.go +++ b/v3/internal/parser/bindings.go @@ -19,12 +19,18 @@ const bindingTemplate = ` /** * {{structName}}.{{methodName}} *Comments - * @param name {string} +* @param names {string} * @returns {Promise} **/ {{methodName}}: function({{inputs}}) { return wails.CallByID({{ID}}, ...Array.prototype.slice.call(arguments, 0)); }, ` +const enumTemplate = ` + export enum {{.EnumName}} { + {{.EnumValues}} + } +` + var reservedWords = []string{ "abstract", "arguments", @@ -119,18 +125,19 @@ func GenerateBinding(structName string, method *BoundMethod) (string, []string, pkgName := getPackageName(input) if pkgName != "" { models = append(models, pkgName) - if input.Type.IsStruct { - nsStruct := input.NamespacedStructType() - namespacedStructs = append(namespacedStructs, nsStruct) - } } - params += " * @param " + inputName + " {" + input.JSType() + "}\n" + if input.Type.IsStruct || input.Type.IsEnum { + nsStruct := input.NamespacedStructType() + namespacedStructs = append(namespacedStructs, nsStruct) + } + + params += " * @param " + inputName + " {" + input.JSType() + "}\n" } params = strings.TrimSuffix(params, "\n") if len(params) == 0 { - params = " *" + params = " *" } - result = strings.ReplaceAll(result, " * @param name {string}", params) + result = strings.ReplaceAll(result, "* @param names {string}", params) var inputs string for _, input := range method.Inputs { pkgName := getPackageName(input) @@ -232,19 +239,8 @@ func GenerateBindings(bindings map[string]map[string][]*BoundMethod) map[string] packageBindings := bindings[packageName] structNames := lo.Keys(packageBindings) sort.Strings(structNames) - 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 { - /** - * The GreetService provides methods to greet a person. - */ - //result[normalisedPackageNames[packageName]] += " /**\n" - //result[normalisedPackageNames[packageName]] += " {{structcomments}}\n" - //result[normalisedPackageNames[packageName]] += " */\n" - result[normalisedPackageNames[packageName]] += " " + structName + ": {\n" + result[normalisedPackageNames[packageName]] += "export const " + structName + " = {\n" methods := packageBindings[structName] sort.Slice(methods, func(i, j int) bool { return methods[i].Name < methods[j].Name @@ -255,9 +251,8 @@ window.go = window.go || {}; allModels = append(allModels, models...) result[normalisedPackageNames[packageName]] += thisBinding } - result[normalisedPackageNames[packageName]] += " },\n" + result[normalisedPackageNames[packageName]] += "};\n\n" } - result[normalisedPackageNames[packageName]] += "};\n" if len(allNamespacedStructs) > 0 { typedefs := "/**\n" diff --git a/v3/internal/parser/bindings_test.go b/v3/internal/parser/bindings_test.go index 1fb2a2c0..15c2495a 100644 --- a/v3/internal/parser/bindings_test.go +++ b/v3/internal/parser/bindings_test.go @@ -27,6 +27,12 @@ func TestGenerateBindings(t *testing.T) { dir string want map[string]string }{ + { + "testdata/enum", + map[string]string{ + "main": getFile("testdata/enum/bindings_main.js"), + }, + }, { "testdata/function_single", map[string]string{ diff --git a/v3/internal/parser/models.go b/v3/internal/parser/models.go index 07ecb305..8ec7a498 100644 --- a/v3/internal/parser/models.go +++ b/v3/internal/parser/models.go @@ -3,6 +3,7 @@ package parser import ( "bytes" "embed" + "github.com/wailsapp/wails/v3/internal/flags" "io" "sort" "strings" @@ -15,16 +16,27 @@ var templates embed.FS type ModelDefinitions struct { Package string Models map[string]*StructDef + Enums map[string]*TypeDef } -func GenerateModel(wr io.Writer, def *ModelDefinitions) error { - tmpl, err := template.New("model.ts.tmpl").ParseFS(templates, "templates/model.ts.tmpl") +func GenerateModel(wr io.Writer, def *ModelDefinitions, options *flags.GenerateBindingsOptions) error { + templateName := "model.ts.tmpl" + if options.UseInterfaces { + templateName = "interfaces.ts.tmpl" + } + + // Fix up TS names + for _, model := range def.Models { + model.Name = options.TSPrefix + model.Name + options.TSSuffix + } + + tmpl, err := template.New(templateName).ParseFS(templates, "templates/"+templateName) if err != nil { println("Unable to create class template: " + err.Error()) return err } - err = tmpl.ExecuteTemplate(wr, "model.ts.tmpl", def) + err = tmpl.ExecuteTemplate(wr, templateName, def) if err != nil { println("Problem executing template: " + err.Error()) return err @@ -42,7 +54,7 @@ func pkgAlias(fullPkg string) string { return pkgParts[len(pkgParts)-1] } -func GenerateModels(models map[packagePath]map[structName]*StructDef) (string, error) { +func GenerateModels(models map[packagePath]map[structName]*StructDef, enums map[packagePath]map[string]*TypeDef, options *flags.GenerateBindingsOptions) (string, error) { if models == nil { return "", nil } @@ -53,7 +65,7 @@ func GenerateModels(models map[packagePath]map[structName]*StructDef) (string, e // sort pkgs by alias (e.g. services) instead of full pkg name (e.g. github.com/wailsapp/wails/somedir/services) // and then sort resulting list by the alias var keys []string - for pkg, _ := range models { + for pkg := range models { keys = append(keys, pkg) } @@ -65,120 +77,11 @@ func GenerateModels(models map[packagePath]map[structName]*StructDef) (string, e err := GenerateModel(&buffer, &ModelDefinitions{ Package: pkgAlias(pkg), Models: models[pkg], - }) + Enums: enums[pkg], + }, options) if err != nil { return "", err } } return buffer.String(), nil } - -//func GenerateClass(wr io.Writer, def *StructDef) error { -// tmpl, err := template.New("class.ts.tmpl").ParseFiles("templates/class.ts.tmpl") -// if err != nil { -// println("Unable to create class template: " + err.Error()) -// return err -// } -// -// err = tmpl.ExecuteTemplate(wr, "class.ts.tmpl", def) -// if err != nil { -// println("Problem executing template: " + err.Error()) -// return err -// } -// return nil -//} - -// -//import ( -// "bytes" -// "fmt" -// "go/ast" -// "go/types" -// "sort" -// "strings" -// "unicode" -//) -// -//func GenerateModels(context *Context) ([]byte, error) { -// var buf bytes.Buffer -// var pkgs []Package -// specs := context.GetBoundStructs() -// for pkg, pkgSpecs := range specs { -// pkgs = append(pkgs, Package{Name: pkg, Specs: pkgSpecs}) -// } -// knownStructs := newAllModels(specs) -// sort.Slice(pkgs, func(i, j int) bool { return pkgs[i].Name < pkgs[j].Name }) -// for _, pkg := range pkgs { -// if _, err := fmt.Fprintf(&buf, "namespace %s {\n", pkg.Name); err != nil { -// return nil, err -// } -// sort.Slice(pkg.Specs, func(i, j int) bool { return pkg.Specs[i].Name.Name < pkg.Specs[j].Name.Name }) -// for _, spec := range pkg.Specs { -// if structType, ok := spec.Type.(*ast.StructType); ok { -// if _, err := fmt.Fprintf(&buf, " class %s {\n", spec.Name.Name); err != nil { -// return nil, err -// } -// -// for _, field := range structType.Fields.List { -// -// // Ignore field names that have a lower case first letter -// if !unicode.IsUpper(rune(field.Names[0].Name[0])) { -// continue -// } -// -// // Get the Go type of the field -// goType := types.ExprString(field.Type) -// // Check if the type is an array -// if arrayType, ok := field.Type.(*ast.ArrayType); ok { -// // Get the element type of the array -// elementType := types.ExprString(arrayType.Elt) -// // Look up the corresponding TypeScript type -// tsType, ok := goToTS[elementType] -// if !ok { -// // strip off the * prefix if it is there -// if strings.HasPrefix(elementType, "*") { -// elementType = elementType[1:] -// } -// if knownStructs.exists(elementType) { -// tsType = elementType -// } else { -// tsType = "any" -// } -// } -// // Output the field as an array of the corresponding TypeScript type -// if _, err := fmt.Fprintf(&buf, " %s: %s[];\n", field.Names[0].Name, tsType); err != nil { -// return nil, err -// } -// } else { -// // strip off the * prefix if it is there -// if strings.HasPrefix(goType, "*") { -// goType = goType[1:] -// } -// // Look up the corresponding TypeScript type -// tsType, ok := goToTS[goType] -// if !ok { -// if knownStructs.exists(goType) { -// tsType = goType -// } else { -// tsType = "any" -// } -// } -// // Output the field as the corresponding TypeScript type -// if _, err := fmt.Fprintf(&buf, " %s: %s;\n", field.Names[0].Name, tsType); err != nil { -// return nil, err -// } -// } -// } -// -// if _, err := fmt.Fprintf(&buf, " }\n"); err != nil { -// return nil, err -// } -// } -// } -// -// if _, err := fmt.Fprintf(&buf, "}\n\n"); err != nil { -// return nil, err -// } -// } -// return buf.Bytes(), nil -//} diff --git a/v3/internal/parser/models_test.go b/v3/internal/parser/models_test.go index f91f0b29..b533f703 100644 --- a/v3/internal/parser/models_test.go +++ b/v3/internal/parser/models_test.go @@ -2,6 +2,7 @@ package parser import ( "github.com/google/go-cmp/cmp" + "github.com/wailsapp/wails/v3/internal/flags" "os" "path/filepath" "strings" @@ -15,40 +16,39 @@ func TestGenerateModels(t *testing.T) { want string }{ { - "testdata/function_single", - "", + dir: "testdata/function_single", }, { - "testdata/function_from_imported_package", - getFile("testdata/function_from_imported_package/models.ts"), + dir: "testdata/function_from_imported_package", + want: getFile("testdata/function_from_imported_package/models.ts"), }, { - "testdata/variable_single", - "", + dir: "testdata/variable_single", }, { - "testdata/variable_single_from_function", - "", + dir: "testdata/variable_single_from_function", }, { - "testdata/variable_single_from_other_function", - getFile("testdata/variable_single_from_other_function/models.ts"), + dir: "testdata/variable_single_from_other_function", + want: getFile("testdata/variable_single_from_other_function/models.ts"), }, { - "testdata/struct_literal_single", - getFile("testdata/struct_literal_single/models.ts"), + dir: "testdata/struct_literal_single", + want: getFile("testdata/struct_literal_single/models.ts"), }, { - "testdata/struct_literal_multiple", - "", + dir: "testdata/struct_literal_multiple", }, { - "testdata/struct_literal_multiple_other", - getFile("testdata/struct_literal_multiple_other/models.ts"), + dir: "testdata/struct_literal_multiple_other", + want: getFile("testdata/struct_literal_multiple_other/models.ts"), }, { - "testdata/struct_literal_multiple_files", - "", + dir: "testdata/struct_literal_multiple_files", + }, + { + dir: "testdata/enum", + want: getFile("testdata/enum/models.ts"), }, } for _, tt := range tests { @@ -60,7 +60,7 @@ func TestGenerateModels(t *testing.T) { } // Generate Models - got, err := GenerateModels(project.Models) + got, err := GenerateModels(project.Models, project.Types, &flags.GenerateBindingsOptions{}) if err != nil { t.Fatalf("GenerateModels() error = %v", err) } diff --git a/v3/internal/parser/parser.go b/v3/internal/parser/parser.go index 90341ca7..2189081d 100644 --- a/v3/internal/parser/parser.go +++ b/v3/internal/parser/parser.go @@ -2,6 +2,7 @@ package parser import ( "fmt" + "github.com/wailsapp/wails/v3/internal/flags" "go/ast" "go/build" "go/parser" @@ -12,6 +13,7 @@ import ( "reflect" "strconv" "strings" + "time" "github.com/samber/lo" "github.com/wailsapp/wails/v3/internal/hash" @@ -26,16 +28,39 @@ type StructDef struct { Fields []*Field } +func (s *StructDef) DefaultValueList() string { + var allFields []string + for _, field := range s.Fields { + thisFieldWithDefaultValue := fmt.Sprintf("%s = %s", field.JSName(), field.DefaultValue()) + allFields = append(allFields, thisFieldWithDefaultValue) + } + return strings.Join(allFields, ", ") +} + type ParameterType struct { Name string IsStruct bool IsSlice bool IsPointer bool + IsEnum bool MapKey *ParameterType MapValue *ParameterType Package string } +type EnumDef struct { + Name string + Filename string + DocComments []string + Values []*EnumValue +} + +type EnumValue struct { + Name string + Value string + DocComments []string +} + type Parameter struct { Name string Type *ParameterType @@ -73,7 +98,7 @@ func (p *Parameter) JSType() string { } // if the type is a struct, we need to add the package name - if p.Type.IsStruct { + if p.Type.IsStruct || p.Type.IsEnum { typeName = p.NamespacedStructType() typeName = strings.ReplaceAll(typeName, ".", "") } @@ -117,7 +142,7 @@ func (f *Field) JSName() string { // via assignment for simple types or constructors for structs func (f *Field) TSBuild(pkg string) string { if !f.Type.IsStruct { - return fmt.Sprintf("source['%s']", f.JSName()) + return fmt.Sprintf("safeSource['%s']", f.JSName()) } if f.Type.Package == "" || f.Type.Package == pkg { @@ -141,7 +166,8 @@ func (f *Field) JSDef(pkg string) string { } var result string - if f.Type.Package == "" || f.Type.Package == pkg { + isExternalStruct := f.Type.Package != "" && f.Type.Package != pkg && f.Type.IsStruct + if f.Type.Package == "" || f.Type.Package == pkg || !isExternalStruct { result += fmt.Sprintf("%s: %s;", f.JSName(), jsType) } else { parts := strings.Split(f.Type.Package, "/") @@ -155,12 +181,45 @@ func (f *Field) JSDef(pkg string) string { return result } +func (f *Field) DefaultValue() string { + // Return the default value of the typescript version of the type as a string + switch f.Type.Name { + case "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uintptr", "float32", "float64", "uint64": + return "0" + case "string": + return `""` + case "bool": + return "false" + default: + return "null" + } +} + +type ConstDef struct { + Name string + DocComment string + Value string +} + +type TypeDef struct { + Name string + DocComments []string + Type string + Consts []*ConstDef + ShouldGenerate bool +} + +func (t *TypeDef) GeneratedName() string { + return t.Name + "Enum" +} + type ParsedPackage struct { Pkg *ast.Package Name string Path string Dir string StructCache map[structName]*StructDef + TypeCache map[string]*TypeDef } type Project struct { @@ -168,7 +227,19 @@ type Project struct { Path string BoundMethods map[packagePath]map[structName][]*BoundMethod Models map[packagePath]map[structName]*StructDef + Types map[packagePath]map[structName]*TypeDef anonymousStructIDCounter int + Stats Stats +} + +type Stats struct { + NumPackages int + NumStructs int + NumMethods int + NumEnums int + NumModels int + StartTime time.Time + EndTime time.Time } func ParseProject(projectPath string) (*Project, error) { @@ -176,6 +247,7 @@ func ParseProject(projectPath string) (*Project, error) { BoundMethods: make(map[packagePath]map[structName][]*BoundMethod), packageCache: make(map[string]*ParsedPackage), } + result.Stats.StartTime = time.Now() pkgs, err := result.parseDirectory(projectPath) if err != nil { return nil, err @@ -195,8 +267,8 @@ func ParseProject(projectPath string) (*Project, error) { return result, nil } -func GenerateBindingsAndModels(projectDir string, outputDir string) error { - p, err := ParseProject(projectDir) +func GenerateBindingsAndModels(options *flags.GenerateBindingsOptions) error { + p, err := ParseProject(options.ProjectDirectory) if err != nil { return err } @@ -204,37 +276,51 @@ func GenerateBindingsAndModels(projectDir string, outputDir string) error { if p.BoundMethods == nil { return nil } - err = os.MkdirAll(outputDir, 0755) + err = os.MkdirAll(options.OutputDirectory, 0755) if err != nil { return err } + p.Stats.NumMethods = len(p.BoundMethods) generatedMethods := GenerateBindings(p.BoundMethods) for pkg, text := range generatedMethods { // Write the file - err = os.WriteFile(filepath.Join(outputDir, "bindings_"+pkg+".js"), []byte(text), 0644) + err = os.WriteFile(filepath.Join(options.OutputDirectory, pkg+".js"), []byte(text), 0644) if err != nil { return err } } + p.Stats.NumModels = len(p.Models) + p.Stats.NumEnums = len(p.Types) + // Generate Models if len(p.Models) > 0 { - generatedModels, err := GenerateModels(p.Models) + generatedModels, err := GenerateModels(p.Models, p.Types, options) if err != nil { return err } - err = os.WriteFile(filepath.Join(outputDir, "models.ts"), []byte(generatedModels), 0644) + err = os.WriteFile(filepath.Join(options.OutputDirectory, options.ModelsFilename), []byte(generatedModels), 0644) if err != nil { return err } } - absPath, err := filepath.Abs(projectDir) + p.Stats.EndTime = time.Now() + + absPath, err := filepath.Abs(options.ProjectDirectory) if err != nil { return err } - println("Generated bindings and models for project: " + absPath) - absPath, err = filepath.Abs(outputDir) + + fmt.Printf("Processed: %s, %s, %s, %s, %s in %s.\n", + pluralise(p.Stats.NumPackages, "Package"), + pluralise(p.Stats.NumStructs, "Struct"), + pluralise(p.Stats.NumMethods, "Method"), + pluralise(p.Stats.NumEnums, "Enum"), + pluralise(p.Stats.NumModels, "Model"), + p.Stats.EndTime.Sub(p.Stats.StartTime).String()) + + absPath, err = filepath.Abs(options.OutputDirectory) if err != nil { return err } @@ -243,6 +329,13 @@ func GenerateBindingsAndModels(projectDir string, outputDir string) error { return nil } +func pluralise(number int, word string) string { + if number == 1 { + return fmt.Sprintf("%d %s", number, word) + } + return fmt.Sprintf("%d %ss", number, word) +} + func (p *Project) parseDirectory(dir string) (map[string]*ParsedPackage, error) { if p.packageCache[dir] != nil { return map[string]*ParsedPackage{dir: p.packageCache[dir]}, nil @@ -261,6 +354,7 @@ func (p *Project) parseDirectory(dir string) (map[string]*ParsedPackage, error) return nil, err } var result = make(map[string]*ParsedPackage) + p.Stats.NumPackages = len(pkgs) for packageName, pkg := range pkgs { parsedPackage := &ParsedPackage{ Pkg: pkg, @@ -268,6 +362,7 @@ func (p *Project) parseDirectory(dir string) (map[string]*ParsedPackage, error) Path: packageName, Dir: getDirectoryForPackage(pkg), StructCache: make(map[structName]*StructDef), + TypeCache: make(map[string]*TypeDef), } p.packageCache[packageName] = parsedPackage result[packageName] = parsedPackage @@ -285,6 +380,28 @@ func (p *Project) findApplicationNewCalls(pkgs map[string]*ParsedPackage) (err e for _, file := range thisPackage.Files { // Use an ast.Inspector to find the calls to application.New ast.Inspect(file, func(n ast.Node) bool { + // Check for const declaration + genDecl, ok := n.(*ast.GenDecl) + if ok { + switch genDecl.Tok { + case token.TYPE: + var comments []string + if genDecl.Doc != nil { + comments = CommentGroupToText(genDecl.Doc) + } + for _, spec := range genDecl.Specs { + if typeSpec, ok := spec.(*ast.TypeSpec); ok { + p.parseTypeDeclaration(typeSpec, pkg, comments) + } + } + case token.CONST: + p.parseConstDeclaration(genDecl, pkg) + default: + } + return true + + } + // Check if the node is a call expression callExpr, ok := n.(*ast.CallExpr) if !ok { @@ -372,6 +489,7 @@ func (p *Project) findApplicationNewCalls(pkgs map[string]*ParsedPackage) (err e return true }) } + p.addTypes(pkg.Path, pkg.TypeCache) if !callFound { return fmt.Errorf("no Bound structs found") } @@ -443,7 +561,7 @@ func (p *Project) parseBoundStructMethods(name string, pkg *ParsedPackage) error method := &BoundMethod{ ID: id, Name: funcDecl.Name.Name, - DocComment: funcDecl.Doc.Text(), + DocComment: strings.TrimSpace(funcDecl.Doc.Text()), Alias: alias, } @@ -464,6 +582,20 @@ func (p *Project) parseBoundStructMethods(name string, pkg *ParsedPackage) error return nil } +func (p *Project) addTypes(packagePath string, types map[string]*TypeDef) { + if types == nil || len(types) == 0 { + return + } + if p.Types == nil { + p.Types = make(map[string]map[string]*TypeDef) + } + _, ok := p.Types[packagePath] + if !ok { + p.Types[packagePath] = make(map[string]*TypeDef) + } + p.Types[packagePath] = types +} + func (p *Project) parseParameters(params *ast.FieldList, pkg *ParsedPackage) []*Parameter { var result []*Parameter for _, field := range params.List { @@ -489,11 +621,21 @@ func (p *Project) parseParameters(params *ast.FieldList, pkg *ParsedPackage) []* } func (p *Project) parseParameterType(field *ast.Field, pkg *ParsedPackage) *ParameterType { - result := &ParameterType{} + result := &ParameterType{ + Package: pkg.Path, + } result.Name = getTypeString(field.Type) switch t := field.Type.(type) { case *ast.Ident: result.IsStruct = isStructType(t) + if !result.IsStruct { + // Check if it's a type alias + typeDef, ok := pkg.TypeCache[t.Name] + if ok { + typeDef.ShouldGenerate = true + result.IsEnum = true + } + } case *ast.StarExpr: result = p.parseParameterType(&ast.Field{Type: t.X}, pkg) result.IsPointer = true @@ -597,9 +739,9 @@ func (p *Project) parseStructFields(structType *ast.StructType, pkg *ParsedPacka if !ok { p.getStructDef(paramType.Name, pkg) } - if paramType.Package == "" { - paramType.Package = pkg.Path - } + } + if paramType.Package == "" { + paramType.Package = pkg.Path } thisField.Type = paramType result = append(result, thisField) @@ -822,6 +964,72 @@ func (p *Project) getFunctionFromName(name string, parsedPackage *ParsedPackage) return nil, fmt.Errorf("function not found") } +func (p *Project) parseTypeDeclaration(decl *ast.TypeSpec, pkg *ParsedPackage, comments []string) { + switch t := decl.Type.(type) { + case *ast.Ident: + switch t.Name { + case "int", "int8", "int16", "int32", "int64", "uint", "uint8", "uint16", "uint32", "uint64", + "uintptr", "float32", "float64", "string", "bool": + // Store this in the type cache + pkg.TypeCache[decl.Name.Name] = &TypeDef{ + Name: decl.Name.Name, + Type: t.Name, + DocComments: TrimSlice(comments), + } + } + } +} + +func (p *Project) parseConstDeclaration(decl *ast.GenDecl, pkg *ParsedPackage) { + // Check if the type of the constant is in the type cache and if it doesn't exist, return + var latestValues []ast.Expr + + for _, spec := range decl.Specs { + valueSpec, ok := spec.(*ast.ValueSpec) + if !ok { + continue + } + // Extract the Type + typeString := getTypeString(valueSpec.Type) + if typeString == "" { + continue + } + // Check if the type is in the type cache + typeDecl, ok := pkg.TypeCache[typeString] + if !ok { + continue + } + + // Get the latest values + if len(valueSpec.Values) > 0 { + latestValues = valueSpec.Values + } + + // Iterate over the names + for index, name := range valueSpec.Names { + constDecl := &ConstDef{ + Name: name.Name, + Value: typeString, + } + + // Get the value + if len(latestValues) > 0 { + switch t := latestValues[index].(type) { + case *ast.BasicLit: + constDecl.Value = t.Value + case *ast.Ident: + constDecl.Value = t.Name + } + } + + if valueSpec.Doc != nil { + constDecl.DocComment = strings.TrimSpace(valueSpec.Doc.Text()) + } + typeDecl.Consts = append(typeDecl.Consts, constDecl) + } + } +} + func getTypeString(expr ast.Expr) string { switch t := expr.(type) { case *ast.Ident: @@ -852,7 +1060,10 @@ func isStructType(expr ast.Expr) bool { case *ast.SliceExpr: return isStructType(e.X) case *ast.Ident: - return e.Obj != nil && e.Obj.Kind == ast.Typ + if e.Obj != nil && e.Obj.Kind == ast.Typ { + return isStructType(e.Obj.Decl.(*ast.TypeSpec).Type) + } + return false default: return false } @@ -869,3 +1080,21 @@ func getDirectoryForPackage(pkg *ast.Package) string { } return "" } + +func CommentGroupToText(comments *ast.CommentGroup) []string { + if comments == nil { + return nil + } + var result []string + for _, comment := range comments.List { + result = append(result, strings.TrimSpace(comment.Text)) + } + return result +} + +func TrimSlice(comments []string) []string { + for i, comment := range comments { + comments[i] = strings.TrimSpace(comment) + } + return comments +} diff --git a/v3/internal/parser/parser_enum_test.go b/v3/internal/parser/parser_enum_test.go new file mode 100644 index 00000000..3d3926ac --- /dev/null +++ b/v3/internal/parser/parser_enum_test.go @@ -0,0 +1,162 @@ +package parser + +import ( + "reflect" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestParseEnum(t *testing.T) { + tests := []struct { + name string + dir string + wantBoundMethods map[string]map[string][]*BoundMethod + wantEnums map[string]map[string]*EnumDef + wantModels map[string]map[string]*StructDef + wantTypes map[string]map[string]*TypeDef + wantErr bool + }{ + { + name: "should find a bound services with an enum", + dir: "testdata/enum", + wantErr: false, + wantBoundMethods: map[string]map[string][]*BoundMethod{ + "main": { + "GreetService": { + { + Name: "Greet", + DocComment: "Greet does XYZ", + Inputs: []*Parameter{ + { + Name: "name", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + { + Name: "title", + Type: &ParameterType{ + Package: "main", + Name: "Title", + IsEnum: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Name: "", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + ID: 1411160069, + }, + { + Name: "NewPerson", + DocComment: "NewPerson creates a new person", + Inputs: []*Parameter{ + { + Name: "name", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "Person", + IsStruct: true, + IsPointer: true, + }, + }, + }, + ID: 1661412647, + }, + }, + }, + }, + wantTypes: map[string]map[string]*TypeDef{ + "main": { + "Title": { + Name: "Title", + Type: "string", + Consts: []*ConstDef{ + { + Name: "Mister", + DocComment: "Mister is a title", + Value: `"Mr"`, + }, + { + Name: "Miss", + Value: `"Miss"`, + }, + { + Name: "Ms", + Value: `"Ms"`, + }, + { + Name: "Mrs", + Value: `"Mrs"`, + }, + { + Name: "Dr", + Value: `"Dr"`, + }, + }, + ShouldGenerate: true, + }, + }, + }, + wantModels: map[string]map[string]*StructDef{ + "main": { + "Person": { + Name: "Person", + Fields: []*Field{ + { + Name: "Title", + Type: &ParameterType{ + Package: "main", + Name: "Title", + IsEnum: true, + }, + }, + { + Name: "Name", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ParseProject(tt.dir) + if (err != nil) != tt.wantErr { + t.Errorf("ParseDirectory() error = %v, wantErr %v", err, tt.wantErr) + return + } + if diff := cmp.Diff(tt.wantBoundMethods, got.BoundMethods); diff != "" { + t.Errorf("ParseDirectory() failed:\n" + diff) + } + if !reflect.DeepEqual(tt.wantModels, got.Models) { + t.Errorf("ParseDirectory() failed:\n" + cmp.Diff(tt.wantModels, got.Models)) + } + if diff := cmp.Diff(tt.wantTypes, got.Types); diff != "" { + t.Errorf("ParseDirectory() failed:\n" + diff) + } + }) + } + +} diff --git a/v3/internal/parser/parser_function_test.go b/v3/internal/parser/parser_function_test.go new file mode 100644 index 00000000..f19e797f --- /dev/null +++ b/v3/internal/parser/parser_function_test.go @@ -0,0 +1,204 @@ +package parser + +import ( + "reflect" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestParseFunction(t *testing.T) { + tests := []struct { + name string + dir string + wantBoundMethods map[string]map[string][]*BoundMethod + wantEnums map[string]map[string]*EnumDef + wantModels map[string]map[string]*StructDef + wantTypes map[string]map[string]*TypeDef + wantErr bool + }{ + { + name: "should find a bound service returned from a function call", + dir: "testdata/function_single", + wantErr: false, + wantBoundMethods: map[string]map[string][]*BoundMethod{ + "main": { + "GreetService": { + { + Name: "Greet", + DocComment: "Greet someone", + Inputs: []*Parameter{ + { + Name: "name", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + Outputs: []*Parameter{ + { + Name: "", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + ID: 1411160069, + }, + }, + }, + }, + }, + { + name: "should find a bound service returned from a function call in another package", + dir: "testdata/function_from_imported_package", + wantErr: false, + wantBoundMethods: map[string]map[string][]*BoundMethod{ + "main": { + "GreetService": { + { + Name: "Greet", + DocComment: "Greet does XYZ", + Inputs: []*Parameter{ + { + Name: "name", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + Outputs: []*Parameter{ + { + Name: "", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + ID: 1411160069, + }, + { + Name: "NewPerson", + DocComment: "NewPerson creates a new person", + Inputs: []*Parameter{ + { + Name: "name", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + Outputs: []*Parameter{ + { + Name: "", + Type: &ParameterType{ + Package: "main", + Name: "Person", + IsPointer: true, + IsStruct: true, + }, + }, + }, + ID: 1661412647, + }, + }, + }, + "github.com/wailsapp/wails/v3/internal/parser/testdata/variable_single_from_other_function/services": { + "OtherService": { + { + Name: "Yay", + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Name: "Address", + IsStruct: true, + IsPointer: true, + Package: "github.com/wailsapp/wails/v3/internal/parser/testdata/variable_single_from_other_function/services", + }, + }, + }, + ID: 302702907, + }, + }, + }, + }, + wantModels: map[string]map[string]*StructDef{ + "main": { + "Person": { + Name: "Person", + Fields: []*Field{ + { + Name: "Name", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + { + Name: "Address", + Type: &ParameterType{ + Name: "Address", + IsStruct: true, + IsPointer: true, + Package: "github.com/wailsapp/wails/v3/internal/parser/testdata/variable_single_from_other_function/services", + }, + }, + }, + }, + }, + "github.com/wailsapp/wails/v3/internal/parser/testdata/variable_single_from_other_function/services": { + "Address": { + Name: "Address", + Fields: []*Field{ + { + Name: "Street", + Type: &ParameterType{ + Package: "github.com/wailsapp/wails/v3/internal/parser/testdata/variable_single_from_other_function/services", + Name: "string", + }, + }, + { + Name: "State", + Type: &ParameterType{ + Package: "github.com/wailsapp/wails/v3/internal/parser/testdata/variable_single_from_other_function/services", + Name: "string", + }, + }, + { + Name: "Country", + Type: &ParameterType{ + Package: "github.com/wailsapp/wails/v3/internal/parser/testdata/variable_single_from_other_function/services", + Name: "string", + }, + }, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ParseProject(tt.dir) + if (err != nil) != tt.wantErr { + t.Errorf("ParseDirectory() error = %v, wantErr %v", err, tt.wantErr) + return + } + if diff := cmp.Diff(tt.wantBoundMethods, got.BoundMethods); diff != "" { + t.Errorf("ParseDirectory() failed:\n" + diff) + } + if !reflect.DeepEqual(tt.wantModels, got.Models) { + t.Errorf("ParseDirectory() failed:\n" + cmp.Diff(tt.wantModels, got.Models)) + } + if diff := cmp.Diff(tt.wantTypes, got.Types); diff != "" { + t.Errorf("ParseDirectory() failed:\n" + diff) + } + }) + } + +} diff --git a/v3/internal/parser/parser_struct_literal_multiple_test.go b/v3/internal/parser/parser_struct_literal_multiple_test.go new file mode 100644 index 00000000..59eec6f4 --- /dev/null +++ b/v3/internal/parser/parser_struct_literal_multiple_test.go @@ -0,0 +1,250 @@ +package parser + +import ( + "reflect" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestParseStructLiteralMultiple(t *testing.T) { + tests := []struct { + name string + dir string + wantBoundMethods map[string]map[string][]*BoundMethod + wantEnums map[string]map[string]*EnumDef + wantModels map[string]map[string]*StructDef + wantTypes map[string]map[string]*TypeDef + wantErr bool + }{ + { + name: "should find multiple bound services", + dir: "testdata/struct_literal_multiple", + wantBoundMethods: map[string]map[string][]*BoundMethod{ + "main": { + "GreetService": { + { + Name: "Greet", + DocComment: "", + Inputs: []*Parameter{ + { + Name: "name", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + Outputs: []*Parameter{ + { + Name: "", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + ID: 1411160069, + }, + }, + "OtherService": { + { + Name: "Hello", + ID: 4249972365, + }, + }, + }, + }, + wantErr: false, + }, + { + name: "should find multiple bound services over multiple files", + dir: "testdata/struct_literal_multiple_files", + wantBoundMethods: map[string]map[string][]*BoundMethod{ + "main": { + "GreetService": { + { + Name: "Greet", + DocComment: "", + Inputs: []*Parameter{ + { + Name: "name", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + Outputs: []*Parameter{ + { + Name: "", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + ID: 1411160069, + }, + }, + "OtherService": { + { + Name: "Hello", + ID: 4249972365, + }, + }, + }, + }, + wantErr: false, + }, + { + name: "should find multiple bound services over multiple packages", + dir: "testdata/struct_literal_multiple_other", + wantErr: false, + wantBoundMethods: map[string]map[string][]*BoundMethod{ + "main": { + "GreetService": { + { + Name: "Greet", + DocComment: "Greet does XYZ", + Inputs: []*Parameter{ + { + Name: "name", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + Outputs: []*Parameter{ + { + Name: "", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + ID: 1411160069, + }, + { + Name: "NewPerson", + DocComment: "NewPerson creates a new person", + Inputs: []*Parameter{ + { + Name: "name", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + Outputs: []*Parameter{ + { + Name: "", + Type: &ParameterType{ + Package: "main", + Name: "Person", + IsPointer: true, + IsStruct: true, + }, + }, + }, + ID: 1661412647, + }, + }, + }, + "github.com/wailsapp/wails/v3/internal/parser/testdata/struct_literal_multiple_other/services": { + "OtherService": { + { + Name: "Yay", + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Name: "Address", + IsStruct: true, + IsPointer: true, + Package: "github.com/wailsapp/wails/v3/internal/parser/testdata/struct_literal_multiple_other/services", + }, + }, + }, + ID: 469445984, + }, + }, + }, + }, + wantModels: map[string]map[string]*StructDef{ + "main": { + "Person": { + Name: "Person", + Fields: []*Field{ + { + Name: "Name", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + { + Name: "Address", + Type: &ParameterType{ + Name: "Address", + IsStruct: true, + IsPointer: true, + Package: "github.com/wailsapp/wails/v3/internal/parser/testdata/struct_literal_multiple_other/services", + }, + }, + }, + }, + }, + "github.com/wailsapp/wails/v3/internal/parser/testdata/struct_literal_multiple_other/services": { + "Address": { + Name: "Address", + Fields: []*Field{ + { + Name: "Street", + Type: &ParameterType{ + Package: "github.com/wailsapp/wails/v3/internal/parser/testdata/struct_literal_multiple_other/services", + Name: "string", + }, + }, + { + Name: "State", + Type: &ParameterType{ + Package: "github.com/wailsapp/wails/v3/internal/parser/testdata/struct_literal_multiple_other/services", + Name: "string", + }, + }, + { + Name: "Country", + Type: &ParameterType{ + Package: "github.com/wailsapp/wails/v3/internal/parser/testdata/struct_literal_multiple_other/services", + Name: "string", + }, + }, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ParseProject(tt.dir) + if (err != nil) != tt.wantErr { + t.Errorf("ParseDirectory() error = %v, wantErr %v", err, tt.wantErr) + return + } + if diff := cmp.Diff(tt.wantBoundMethods, got.BoundMethods); diff != "" { + t.Errorf("ParseDirectory() failed:\n" + diff) + } + if !reflect.DeepEqual(tt.wantModels, got.Models) { + t.Errorf("ParseDirectory() failed:\n" + cmp.Diff(tt.wantModels, got.Models)) + } + if diff := cmp.Diff(tt.wantTypes, got.Types); diff != "" { + t.Errorf("ParseDirectory() failed:\n" + diff) + } + }) + } + +} diff --git a/v3/internal/parser/parser_struct_literal_non_pointer_single_test.go b/v3/internal/parser/parser_struct_literal_non_pointer_single_test.go new file mode 100644 index 00000000..b99affd9 --- /dev/null +++ b/v3/internal/parser/parser_struct_literal_non_pointer_single_test.go @@ -0,0 +1,1091 @@ +package parser + +import ( + "reflect" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestParseStructLiteralNonPointerSingle(t *testing.T) { + tests := []struct { + name string + dir string + wantBoundMethods map[string]map[string][]*BoundMethod + wantEnums map[string]map[string]*EnumDef + wantModels map[string]map[string]*StructDef + wantTypes map[string]map[string]*TypeDef + wantErr bool + }{ + { + name: "should find single bound service (non-pointer receiver)", + dir: "testdata/struct_literal_non_pointer_single", + wantBoundMethods: map[string]map[string][]*BoundMethod{ + "main": { + "GreetService": { + { + Name: "Greet", + DocComment: "Greet someone", + Inputs: []*Parameter{ + { + Name: "name", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + Outputs: []*Parameter{ + { + Name: "", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + ID: 1411160069, + }, + { + Name: "NoInputsStringOut", + DocComment: "", + Inputs: nil, + Outputs: []*Parameter{ + { + Name: "", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + ID: 1075577233, + }, + { + Name: "StringArrayInputStringOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "string", + IsSlice: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + ID: 1091960237, + }, + { + Name: "StringArrayInputStringArrayOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "string", + IsSlice: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "string", + IsSlice: true, + }, + }, + }, + ID: 383995060, + }, + { + Name: "StringArrayInputNamedOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "string", + IsSlice: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Name: "output", + Type: &ParameterType{ + Package: "main", + Name: "string", + IsSlice: true, + }, + }, + }, + ID: 3678582682, + }, + { + Name: "StringArrayInputNamedOutputs", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "string", + IsSlice: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Name: "output", + Type: &ParameterType{ + Package: "main", + Name: "string", + IsSlice: true, + }, + }, + { + Name: "err", + Type: &ParameterType{ + Package: "main", + Name: "error", + }, + }, + }, + ID: 319259595, + }, + { + Name: "IntPointerInputNamedOutputs", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "int", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Name: "output", + Type: &ParameterType{ + Package: "main", + Name: "int", + IsPointer: true, + }, + }, + { + Name: "err", + Type: &ParameterType{ + Package: "main", + Name: "error", + }}, + }, + ID: 2718999663, + }, + { + Name: "UIntPointerInAndOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "uint", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "uint", + IsPointer: true, + }, + }, + }, + ID: 1367187362, + }, + { + Name: "UInt8PointerInAndOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "uint8", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "uint8", + IsPointer: true, + }, + }, + }, + ID: 518250834, + }, + { + Name: "UInt16PointerInAndOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "uint16", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "uint16", + IsPointer: true, + }, + }, + }, + ID: 1236957573, + }, + { + Name: "UInt32PointerInAndOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "uint32", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "uint32", + IsPointer: true, + }, + }, + }, + ID: 1739300671, + }, + { + Name: "UInt64PointerInAndOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "uint64", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "uint64", + IsPointer: true, + }, + }, + }, + ID: 1403757716, + }, + { + Name: "IntPointerInAndOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "int", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "int", + IsPointer: true, + }, + }, + }, + ID: 1066151743, + }, + { + Name: "Int8PointerInAndOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "int8", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "int8", + IsPointer: true, + }, + }, + }, + ID: 2189402897, + }, + { + Name: "Int16PointerInAndOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "int16", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "int16", + IsPointer: true, + }, + }, + }, + ID: 1754277916, + }, + { + Name: "Int32PointerInAndOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "int32", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "int32", + IsPointer: true, + }, + }, + }, + ID: 4251088558, + }, + { + Name: "Int64PointerInAndOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "int64", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "int64", + IsPointer: true, + }, + }, + }, + ID: 2205561041, + }, + { + Name: "IntInIntOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "int", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "int", + }, + }, + }, + ID: 642881729, + }, + { + Name: "Int8InIntOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "int8", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "int8", + }, + }, + }, + ID: 572240879, + }, + { + Name: "Int16InIntOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "int16", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "int16", + }, + }, + }, + ID: 3306292566, + }, + { + Name: "Int32InIntOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "int32", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "int32", + }, + }, + }, + ID: 1909469092, + }, + { + Name: "Int64InIntOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "int64", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "int64", + }, + }, + }, + ID: 1343888303, + }, + { + Name: "UIntInUIntOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "uint", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "uint", + }, + }, + }, + ID: 2836661285, + }, + { + Name: "UInt8InUIntOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "uint8", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "uint8", + }, + }, + }, + ID: 2988345717, + }, + { + Name: "UInt16InUIntOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "uint16", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "uint16", + }, + }, + }, + ID: 3401034892, + }, + { + Name: "UInt32InUIntOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "uint32", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "uint32", + }, + }, + }, + ID: 1160383782, + }, + { + Name: "UInt64InUIntOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "uint64", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "uint64", + }, + }, + }, + ID: 793803239, + }, + { + Name: "Float32InFloat32Out", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "float32", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "float32", + }, + }, + }, + ID: 3132595881, + }, + { + Name: "Float64InFloat64Out", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "float64", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "float64", + }, + }, + }, + ID: 2182412247, + }, + { + Name: "PointerFloat32InFloat32Out", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "float32", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "float32", + IsPointer: true, + }, + }, + }, + ID: 224675106, + }, + { + Name: "PointerFloat64InFloat64Out", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "float64", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "float64", + IsPointer: true, + }, + }, + }, + ID: 2124953624, + }, + { + Name: "BoolInBoolOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "bool", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "bool", + }, + }, + }, + ID: 2424639793, + }, + { + Name: "PointerBoolInBoolOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "bool", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "bool", + IsPointer: true, + }, + }, + }, + ID: 3589606958, + }, + { + Name: "PointerStringInStringOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "string", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "string", + IsPointer: true, + }, + }, + }, + ID: 229603958, + }, + { + Name: "StructPointerInputErrorOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "Person", + IsPointer: true, + IsStruct: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "error", + }, + }, + }, + ID: 2447692557, + }, + { + Name: "StructInputStructOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "Person", + IsStruct: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "Person", + IsStruct: true, + }, + }, + }, + ID: 3835643147, + }, + { + Name: "StructPointerInputStructPointerOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "Person", + IsPointer: true, + IsStruct: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "Person", + IsPointer: true, + IsStruct: true, + }, + }, + }, + ID: 2943477349, + }, + { + Name: "MapIntInt", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "map", + MapKey: &ParameterType{ + Name: "int", + Package: "main", + }, + MapValue: &ParameterType{ + Name: "int", + Package: "main", + }, + }, + }, + }, + ID: 2386486356, + }, + { + Name: "PointerMapIntInt", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "map", + IsPointer: true, + MapKey: &ParameterType{ + Name: "int", + Package: "main", + }, + MapValue: &ParameterType{ + Name: "int", + Package: "main", + }, + }, + }, + }, + ID: 3516977899, + }, + { + Name: "MapIntPointerInt", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "map", + MapKey: &ParameterType{ + Name: "int", + IsPointer: true, + Package: "main", + }, + MapValue: &ParameterType{ + Name: "int", + Package: "main", + }, + }, + }, + }, + ID: 550413585, + }, + { + Name: "MapIntSliceInt", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "map", + MapKey: &ParameterType{ + Name: "int", + Package: "main", + }, + MapValue: &ParameterType{ + Name: "int", + IsSlice: true, + Package: "main", + }, + }, + }, + }, + ID: 2900172572, + }, + { + Name: "MapIntSliceIntInMapIntSliceIntOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "map", + MapKey: &ParameterType{ + Name: "int", + Package: "main", + }, + MapValue: &ParameterType{ + Name: "int", + IsSlice: true, + Package: "main", + }, + }, + }, + }, + Outputs: []*Parameter{ + { + Name: "out", + Type: &ParameterType{ + Package: "main", + Name: "map", + MapKey: &ParameterType{ + Name: "int", + Package: "main", + }, + MapValue: &ParameterType{ + Name: "int", + IsSlice: true, + Package: "main", + }, + }, + }, + }, + ID: 881980169, + }, + { + Name: "ArrayInt", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "int", + IsSlice: true, + }, + }, + }, + ID: 3862002418, + }, + }, + }, + }, + wantModels: map[string]map[string]*StructDef{ + "main": { + "Person": { + Name: "Person", + Fields: []*Field{ + { + Name: "Name", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + { + Name: "Parent", + Type: &ParameterType{ + Package: "main", + Name: "Person", + IsStruct: true, + IsPointer: true, + }, + }, + { + Name: "Details", + Type: &ParameterType{ + Package: "main", + Name: "anon1", + IsStruct: true, + }, + }, + }, + }, + "anon1": { + Name: "anon1", + Fields: []*Field{ + { + Name: "Age", + Type: &ParameterType{ + Package: "main", + Name: "int", + }, + }, + { + Name: "Address", + Type: &ParameterType{ + Package: "main", + Name: "anon2", + IsStruct: true, + }, + }, + }, + }, + "anon2": { + Name: "anon2", + Fields: []*Field{ + { + Name: "Street", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + }, + }, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ParseProject(tt.dir) + if (err != nil) != tt.wantErr { + t.Errorf("ParseDirectory() error = %v, wantErr %v", err, tt.wantErr) + return + } + if diff := cmp.Diff(tt.wantBoundMethods, got.BoundMethods); diff != "" { + t.Errorf("ParseDirectory() failed:\n" + diff) + } + if !reflect.DeepEqual(tt.wantModels, got.Models) { + t.Errorf("ParseDirectory() failed:\n" + cmp.Diff(tt.wantModels, got.Models)) + } + if diff := cmp.Diff(tt.wantTypes, got.Types); diff != "" { + t.Errorf("ParseDirectory() failed:\n" + diff) + } + }) + } + +} diff --git a/v3/internal/parser/parser_struct_literal_single_test.go b/v3/internal/parser/parser_struct_literal_single_test.go new file mode 100644 index 00000000..dd3fefb3 --- /dev/null +++ b/v3/internal/parser/parser_struct_literal_single_test.go @@ -0,0 +1,1092 @@ +package parser + +import ( + "reflect" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestParseStructLiteralSingle(t *testing.T) { + tests := []struct { + name string + dir string + wantBoundMethods map[string]map[string][]*BoundMethod + wantEnums map[string]map[string]*EnumDef + wantModels map[string]map[string]*StructDef + wantTypes map[string]map[string]*TypeDef + wantErr bool + }{ + { + name: "should find single bound service", + dir: "testdata/struct_literal_single", + //wantModels: []string{"main.GreetService"}, + wantBoundMethods: map[string]map[string][]*BoundMethod{ + "main": { + "GreetService": { + { + Name: "Greet", + DocComment: "Greet someone", + Inputs: []*Parameter{ + { + Name: "name", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + Outputs: []*Parameter{ + { + Name: "", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + ID: 1411160069, + }, + { + Name: "NoInputsStringOut", + DocComment: "", + Inputs: nil, + Outputs: []*Parameter{ + { + Name: "", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + ID: 1075577233, + }, + { + Name: "StringArrayInputStringOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "string", + IsSlice: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + ID: 1091960237, + }, + { + Name: "StringArrayInputStringArrayOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "string", + IsSlice: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "string", + IsSlice: true, + }, + }, + }, + ID: 383995060, + }, + { + Name: "StringArrayInputNamedOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "string", + IsSlice: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Name: "output", + Type: &ParameterType{ + Package: "main", + Name: "string", + IsSlice: true, + }, + }, + }, + ID: 3678582682, + }, + { + Name: "StringArrayInputNamedOutputs", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "string", + IsSlice: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Name: "output", + Type: &ParameterType{ + Package: "main", + Name: "string", + IsSlice: true, + }, + }, + { + Name: "err", + Type: &ParameterType{ + Package: "main", + Name: "error", + }, + }, + }, + ID: 319259595, + }, + { + Name: "IntPointerInputNamedOutputs", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "int", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Name: "output", + Type: &ParameterType{ + Package: "main", + Name: "int", + IsPointer: true, + }, + }, + { + Name: "err", + Type: &ParameterType{ + Package: "main", + Name: "error", + }}, + }, + ID: 2718999663, + }, + { + Name: "UIntPointerInAndOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "uint", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "uint", + IsPointer: true, + }, + }, + }, + ID: 1367187362, + }, + { + Name: "UInt8PointerInAndOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "uint8", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "uint8", + IsPointer: true, + }, + }, + }, + ID: 518250834, + }, + { + Name: "UInt16PointerInAndOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "uint16", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "uint16", + IsPointer: true, + }, + }, + }, + ID: 1236957573, + }, + { + Name: "UInt32PointerInAndOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "uint32", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "uint32", + IsPointer: true, + }, + }, + }, + ID: 1739300671, + }, + { + Name: "UInt64PointerInAndOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "uint64", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "uint64", + IsPointer: true, + }, + }, + }, + ID: 1403757716, + }, + { + Name: "IntPointerInAndOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "int", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "int", + IsPointer: true, + }, + }, + }, + ID: 1066151743, + }, + { + Name: "Int8PointerInAndOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "int8", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "int8", + IsPointer: true, + }, + }, + }, + ID: 2189402897, + }, + { + Name: "Int16PointerInAndOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "int16", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "int16", + IsPointer: true, + }, + }, + }, + ID: 1754277916, + }, + { + Name: "Int32PointerInAndOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "int32", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "int32", + IsPointer: true, + }, + }, + }, + ID: 4251088558, + }, + { + Name: "Int64PointerInAndOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "int64", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "int64", + IsPointer: true, + }, + }, + }, + ID: 2205561041, + }, + { + Name: "IntInIntOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "int", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "int", + }, + }, + }, + ID: 642881729, + }, + { + Name: "Int8InIntOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "int8", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "int8", + }, + }, + }, + ID: 572240879, + }, + { + Name: "Int16InIntOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "int16", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "int16", + }, + }, + }, + ID: 3306292566, + }, + { + Name: "Int32InIntOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "int32", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "int32", + }, + }, + }, + ID: 1909469092, + }, + { + Name: "Int64InIntOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "int64", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "int64", + }, + }, + }, + ID: 1343888303, + }, + { + Name: "UIntInUIntOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "uint", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "uint", + }, + }, + }, + ID: 2836661285, + }, + { + Name: "UInt8InUIntOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "uint8", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "uint8", + }, + }, + }, + ID: 2988345717, + }, + { + Name: "UInt16InUIntOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "uint16", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "uint16", + }, + }, + }, + ID: 3401034892, + }, + { + Name: "UInt32InUIntOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "uint32", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "uint32", + }, + }, + }, + ID: 1160383782, + }, + { + Name: "UInt64InUIntOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "uint64", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "uint64", + }, + }, + }, + ID: 793803239, + }, + { + Name: "Float32InFloat32Out", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "float32", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "float32", + }, + }, + }, + ID: 3132595881, + }, + { + Name: "Float64InFloat64Out", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "float64", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "float64", + }, + }, + }, + ID: 2182412247, + }, + { + Name: "PointerFloat32InFloat32Out", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "float32", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "float32", + IsPointer: true, + }, + }, + }, + ID: 224675106, + }, + { + Name: "PointerFloat64InFloat64Out", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "float64", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "float64", + IsPointer: true, + }, + }, + }, + ID: 2124953624, + }, + { + Name: "BoolInBoolOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "bool", + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "bool", + }, + }, + }, + ID: 2424639793, + }, + { + Name: "PointerBoolInBoolOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "bool", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "bool", + IsPointer: true, + }, + }, + }, + ID: 3589606958, + }, + { + Name: "PointerStringInStringOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "string", + IsPointer: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "string", + IsPointer: true, + }, + }, + }, + ID: 229603958, + }, + { + Name: "StructPointerInputErrorOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "Person", + IsPointer: true, + IsStruct: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "error", + }, + }, + }, + ID: 2447692557, + }, + { + Name: "StructInputStructOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "Person", + IsStruct: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "Person", + IsStruct: true, + }, + }, + }, + ID: 3835643147, + }, + { + Name: "StructPointerInputStructPointerOutput", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "Person", + IsPointer: true, + IsStruct: true, + }, + }, + }, + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Package: "main", + Name: "Person", + IsPointer: true, + IsStruct: true, + }, + }, + }, + ID: 2943477349, + }, + { + Name: "MapIntInt", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "map", + MapKey: &ParameterType{ + Name: "int", + Package: "main", + }, + MapValue: &ParameterType{ + Name: "int", + Package: "main", + }, + }, + }, + }, + ID: 2386486356, + }, + { + Name: "PointerMapIntInt", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "map", + IsPointer: true, + MapKey: &ParameterType{ + Name: "int", + Package: "main", + }, + MapValue: &ParameterType{ + Name: "int", + Package: "main", + }, + }, + }, + }, + ID: 3516977899, + }, + { + Name: "MapIntPointerInt", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "map", + MapKey: &ParameterType{ + Name: "int", + IsPointer: true, + Package: "main", + }, + MapValue: &ParameterType{ + Name: "int", + Package: "main", + }, + }, + }, + }, + ID: 550413585, + }, + { + Name: "MapIntSliceInt", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "map", + MapKey: &ParameterType{ + Name: "int", + Package: "main", + }, + MapValue: &ParameterType{ + Name: "int", + IsSlice: true, + Package: "main", + }, + }, + }, + }, + ID: 2900172572, + }, + { + Name: "MapIntSliceIntInMapIntSliceIntOut", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "map", + MapKey: &ParameterType{ + Name: "int", + Package: "main", + }, + MapValue: &ParameterType{ + Name: "int", + IsSlice: true, + Package: "main", + }, + }, + }, + }, + Outputs: []*Parameter{ + { + Name: "out", + Type: &ParameterType{ + Package: "main", + Name: "map", + MapKey: &ParameterType{ + Name: "int", + Package: "main", + }, + MapValue: &ParameterType{ + Name: "int", + IsSlice: true, + Package: "main", + }, + }, + }, + }, + ID: 881980169, + }, + { + Name: "ArrayInt", + Inputs: []*Parameter{ + { + Name: "in", + Type: &ParameterType{ + Package: "main", + Name: "int", + IsSlice: true, + }, + }, + }, + ID: 3862002418, + }, + }, + }, + }, + wantModels: map[string]map[string]*StructDef{ + "main": { + "Person": { + Name: "Person", + Fields: []*Field{ + { + Name: "Name", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + { + Name: "Parent", + Type: &ParameterType{ + Package: "main", + Name: "Person", + IsStruct: true, + IsPointer: true, + }, + }, + { + Name: "Details", + Type: &ParameterType{ + Package: "main", + Name: "anon1", + IsStruct: true, + }, + }, + }, + }, + "anon1": { + Name: "anon1", + Fields: []*Field{ + { + Name: "Age", + Type: &ParameterType{ + Package: "main", + Name: "int", + }, + }, + { + Name: "Address", + Type: &ParameterType{ + Package: "main", + Name: "anon2", + IsStruct: true, + }, + }, + }, + }, + "anon2": { + Name: "anon2", + Fields: []*Field{ + { + Name: "Street", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + }, + }, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ParseProject(tt.dir) + if (err != nil) != tt.wantErr { + t.Errorf("ParseDirectory() error = %v, wantErr %v", err, tt.wantErr) + return + } + if diff := cmp.Diff(tt.wantBoundMethods, got.BoundMethods); diff != "" { + t.Errorf("ParseDirectory() failed:\n" + diff) + } + if !reflect.DeepEqual(tt.wantModels, got.Models) { + t.Errorf("ParseDirectory() failed:\n" + cmp.Diff(tt.wantModels, got.Models)) + } + if diff := cmp.Diff(tt.wantTypes, got.Types); diff != "" { + t.Errorf("ParseDirectory() failed:\n" + diff) + } + }) + } + +} diff --git a/v3/internal/parser/parser_test.go b/v3/internal/parser/parser_test.go deleted file mode 100644 index 8722836d..00000000 --- a/v3/internal/parser/parser_test.go +++ /dev/null @@ -1,2577 +0,0 @@ -package parser - -import ( - "testing" - - "github.com/google/go-cmp/cmp" -) - -func TestParseDirectory(t *testing.T) { - tests := []struct { - name string - dir string - wantBoundMethods map[string]map[string][]*BoundMethod - wantModels map[string]map[string]*StructDef - wantErr bool - }{ - { - name: "should find single bound service", - dir: "testdata/struct_literal_single", - //wantModels: []string{"main.GreetService"}, - wantBoundMethods: 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", - }, - }, - }, - ID: 1411160069, - }, - { - Name: "NoInputsStringOut", - DocComment: "", - Inputs: nil, - Outputs: []*Parameter{ - { - Name: "", - Type: &ParameterType{ - Name: "string", - }, - }, - }, - ID: 1075577233, - }, - { - Name: "StringArrayInputStringOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "string", - IsSlice: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "string", - }, - }, - }, - ID: 1091960237, - }, - { - Name: "StringArrayInputStringArrayOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "string", - IsSlice: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "string", - IsSlice: true, - }, - }, - }, - ID: 383995060, - }, - { - Name: "StringArrayInputNamedOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "string", - IsSlice: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Name: "output", - Type: &ParameterType{ - Name: "string", - IsSlice: true, - }, - }, - }, - ID: 3678582682, - }, - { - Name: "StringArrayInputNamedOutputs", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "string", - IsSlice: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Name: "output", - Type: &ParameterType{ - Name: "string", - IsSlice: true, - }, - }, - { - Name: "err", - Type: &ParameterType{ - Name: "error", - }, - }, - }, - ID: 319259595, - }, - { - Name: "IntPointerInputNamedOutputs", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "int", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Name: "output", - Type: &ParameterType{ - Name: "int", - IsPointer: true, - }, - }, - { - Name: "err", - Type: &ParameterType{ - Name: "error", - }}, - }, - ID: 2718999663, - }, - { - Name: "UIntPointerInAndOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "uint", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "uint", - IsPointer: true, - }, - }, - }, - ID: 1367187362, - }, - { - Name: "UInt8PointerInAndOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "uint8", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "uint8", - IsPointer: true, - }, - }, - }, - ID: 518250834, - }, - { - Name: "UInt16PointerInAndOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "uint16", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "uint16", - IsPointer: true, - }, - }, - }, - ID: 1236957573, - }, - { - Name: "UInt32PointerInAndOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "uint32", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "uint32", - IsPointer: true, - }, - }, - }, - ID: 1739300671, - }, - { - Name: "UInt64PointerInAndOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "uint64", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "uint64", - IsPointer: true, - }, - }, - }, - ID: 1403757716, - }, - { - Name: "IntPointerInAndOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "int", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "int", - IsPointer: true, - }, - }, - }, - ID: 1066151743, - }, - { - Name: "Int8PointerInAndOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "int8", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "int8", - IsPointer: true, - }, - }, - }, - ID: 2189402897, - }, - { - Name: "Int16PointerInAndOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "int16", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "int16", - IsPointer: true, - }, - }, - }, - ID: 1754277916, - }, - { - Name: "Int32PointerInAndOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "int32", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "int32", - IsPointer: true, - }, - }, - }, - ID: 4251088558, - }, - { - Name: "Int64PointerInAndOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "int64", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "int64", - IsPointer: true, - }, - }, - }, - ID: 2205561041, - }, - { - Name: "IntInIntOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "int", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "int", - }, - }, - }, - ID: 642881729, - }, - { - Name: "Int8InIntOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "int8", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "int8", - }, - }, - }, - ID: 572240879, - }, - { - Name: "Int16InIntOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "int16", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "int16", - }, - }, - }, - ID: 3306292566, - }, - { - Name: "Int32InIntOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "int32", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "int32", - }, - }, - }, - ID: 1909469092, - }, - { - Name: "Int64InIntOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "int64", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "int64", - }, - }, - }, - ID: 1343888303, - }, - { - Name: "UIntInUIntOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "uint", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "uint", - }, - }, - }, - ID: 2836661285, - }, - { - Name: "UInt8InUIntOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "uint8", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "uint8", - }, - }, - }, - ID: 2988345717, - }, - { - Name: "UInt16InUIntOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "uint16", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "uint16", - }, - }, - }, - ID: 3401034892, - }, - { - Name: "UInt32InUIntOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "uint32", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "uint32", - }, - }, - }, - ID: 1160383782, - }, - { - Name: "UInt64InUIntOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "uint64", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "uint64", - }, - }, - }, - ID: 793803239, - }, - { - Name: "Float32InFloat32Out", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "float32", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "float32", - }, - }, - }, - ID: 3132595881, - }, - { - Name: "Float64InFloat64Out", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "float64", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "float64", - }, - }, - }, - ID: 2182412247, - }, - { - Name: "PointerFloat32InFloat32Out", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "float32", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "float32", - IsPointer: true, - }, - }, - }, - ID: 224675106, - }, - { - Name: "PointerFloat64InFloat64Out", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "float64", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "float64", - IsPointer: true, - }, - }, - }, - ID: 2124953624, - }, - { - Name: "BoolInBoolOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "bool", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "bool", - }, - }, - }, - ID: 2424639793, - }, - { - Name: "PointerBoolInBoolOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "bool", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "bool", - IsPointer: true, - }, - }, - }, - ID: 3589606958, - }, - { - Name: "PointerStringInStringOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "string", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "string", - IsPointer: true, - }, - }, - }, - ID: 229603958, - }, - { - Name: "StructPointerInputErrorOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "Person", - IsPointer: true, - IsStruct: true, - Package: "main", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "error", - }, - }, - }, - ID: 2447692557, - }, - { - Name: "StructInputStructOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "Person", - IsStruct: true, - Package: "main", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "Person", - IsStruct: true, - Package: "main", - }, - }, - }, - ID: 3835643147, - }, - { - Name: "StructPointerInputStructPointerOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "Person", - IsPointer: true, - IsStruct: true, - Package: "main", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "Person", - IsPointer: true, - IsStruct: true, - Package: "main", - }, - }, - }, - ID: 2943477349, - }, - { - Name: "MapIntInt", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "map", - MapKey: &ParameterType{ - Name: "int", - }, - MapValue: &ParameterType{ - Name: "int", - }, - }, - }, - }, - ID: 2386486356, - }, - { - Name: "PointerMapIntInt", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "map", - IsPointer: true, - MapKey: &ParameterType{ - Name: "int", - }, - MapValue: &ParameterType{ - Name: "int", - }, - }, - }, - }, - ID: 3516977899, - }, - { - Name: "MapIntPointerInt", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "map", - MapKey: &ParameterType{ - Name: "int", - IsPointer: true, - }, - MapValue: &ParameterType{ - Name: "int", - }, - }, - }, - }, - ID: 550413585, - }, - { - Name: "MapIntSliceInt", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "map", - MapKey: &ParameterType{ - Name: "int", - }, - MapValue: &ParameterType{ - Name: "int", - IsSlice: true, - }, - }, - }, - }, - ID: 2900172572, - }, - { - Name: "MapIntSliceIntInMapIntSliceIntOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "map", - MapKey: &ParameterType{ - Name: "int", - }, - MapValue: &ParameterType{ - Name: "int", - IsSlice: true, - }, - }, - }, - }, - Outputs: []*Parameter{ - { - Name: "out", - Type: &ParameterType{ - Name: "map", - MapKey: &ParameterType{ - Name: "int", - }, - MapValue: &ParameterType{ - Name: "int", - IsSlice: true, - }, - }, - }, - }, - ID: 881980169, - }, - { - Name: "ArrayInt", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "int", - IsSlice: true, - }, - }, - }, - ID: 3862002418, - }, - }, - }, - }, - wantModels: map[string]map[string]*StructDef{ - "main": { - "Person": { - Name: "Person", - Fields: []*Field{ - { - Name: "Name", - Type: &ParameterType{ - Name: "string", - }, - }, - { - Name: "Parent", - Type: &ParameterType{ - Name: "Person", - IsStruct: true, - IsPointer: true, - Package: "main", - }, - }, - { - Name: "Details", - Type: &ParameterType{ - Name: "anon1", - IsStruct: true, - Package: "main", - }, - }, - }, - }, - "anon1": { - Name: "anon1", - Fields: []*Field{ - { - Name: "Age", - Type: &ParameterType{ - Name: "int", - }, - }, - { - Name: "Address", - Type: &ParameterType{ - Name: "anon2", - IsStruct: true, - Package: "main", - }, - }, - }, - }, - "anon2": { - Name: "anon2", - Fields: []*Field{ - { - Name: "Street", - Type: &ParameterType{ - Name: "string", - }, - }, - }, - }, - }, - }, - wantErr: false, - }, - { - name: "should find single bound service (non-pointer receiver)", - dir: "testdata/struct_literal_non_pointer_single", - wantBoundMethods: 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", - }, - }, - }, - ID: 1411160069, - }, - { - Name: "NoInputsStringOut", - DocComment: "", - Inputs: nil, - Outputs: []*Parameter{ - { - Name: "", - Type: &ParameterType{ - Name: "string", - }, - }, - }, - ID: 1075577233, - }, - { - Name: "StringArrayInputStringOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "string", - IsSlice: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "string", - }, - }, - }, - ID: 1091960237, - }, - { - Name: "StringArrayInputStringArrayOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "string", - IsSlice: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "string", - IsSlice: true, - }, - }, - }, - ID: 383995060, - }, - { - Name: "StringArrayInputNamedOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "string", - IsSlice: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Name: "output", - Type: &ParameterType{ - Name: "string", - IsSlice: true, - }, - }, - }, - ID: 3678582682, - }, - { - Name: "StringArrayInputNamedOutputs", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "string", - IsSlice: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Name: "output", - Type: &ParameterType{ - Name: "string", - IsSlice: true, - }, - }, - { - Name: "err", - Type: &ParameterType{ - Name: "error", - }, - }, - }, - ID: 319259595, - }, - { - Name: "IntPointerInputNamedOutputs", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "int", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Name: "output", - Type: &ParameterType{ - Name: "int", - IsPointer: true, - }, - }, - { - Name: "err", - Type: &ParameterType{ - Name: "error", - }}, - }, - ID: 2718999663, - }, - { - Name: "UIntPointerInAndOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "uint", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "uint", - IsPointer: true, - }, - }, - }, - ID: 1367187362, - }, - { - Name: "UInt8PointerInAndOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "uint8", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "uint8", - IsPointer: true, - }, - }, - }, - ID: 518250834, - }, - { - Name: "UInt16PointerInAndOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "uint16", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "uint16", - IsPointer: true, - }, - }, - }, - ID: 1236957573, - }, - { - Name: "UInt32PointerInAndOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "uint32", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "uint32", - IsPointer: true, - }, - }, - }, - ID: 1739300671, - }, - { - Name: "UInt64PointerInAndOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "uint64", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "uint64", - IsPointer: true, - }, - }, - }, - ID: 1403757716, - }, - { - Name: "IntPointerInAndOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "int", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "int", - IsPointer: true, - }, - }, - }, - ID: 1066151743, - }, - { - Name: "Int8PointerInAndOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "int8", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "int8", - IsPointer: true, - }, - }, - }, - ID: 2189402897, - }, - { - Name: "Int16PointerInAndOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "int16", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "int16", - IsPointer: true, - }, - }, - }, - ID: 1754277916, - }, - { - Name: "Int32PointerInAndOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "int32", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "int32", - IsPointer: true, - }, - }, - }, - ID: 4251088558, - }, - { - Name: "Int64PointerInAndOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "int64", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "int64", - IsPointer: true, - }, - }, - }, - ID: 2205561041, - }, - { - Name: "IntInIntOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "int", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "int", - }, - }, - }, - ID: 642881729, - }, - { - Name: "Int8InIntOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "int8", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "int8", - }, - }, - }, - ID: 572240879, - }, - { - Name: "Int16InIntOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "int16", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "int16", - }, - }, - }, - ID: 3306292566, - }, - { - Name: "Int32InIntOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "int32", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "int32", - }, - }, - }, - ID: 1909469092, - }, - { - Name: "Int64InIntOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "int64", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "int64", - }, - }, - }, - ID: 1343888303, - }, - { - Name: "UIntInUIntOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "uint", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "uint", - }, - }, - }, - ID: 2836661285, - }, - { - Name: "UInt8InUIntOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "uint8", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "uint8", - }, - }, - }, - ID: 2988345717, - }, - { - Name: "UInt16InUIntOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "uint16", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "uint16", - }, - }, - }, - ID: 3401034892, - }, - { - Name: "UInt32InUIntOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "uint32", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "uint32", - }, - }, - }, - ID: 1160383782, - }, - { - Name: "UInt64InUIntOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "uint64", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "uint64", - }, - }, - }, - ID: 793803239, - }, - { - Name: "Float32InFloat32Out", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "float32", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "float32", - }, - }, - }, - ID: 3132595881, - }, - { - Name: "Float64InFloat64Out", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "float64", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "float64", - }, - }, - }, - ID: 2182412247, - }, - { - Name: "PointerFloat32InFloat32Out", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "float32", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "float32", - IsPointer: true, - }, - }, - }, - ID: 224675106, - }, - { - Name: "PointerFloat64InFloat64Out", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "float64", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "float64", - IsPointer: true, - }, - }, - }, - ID: 2124953624, - }, - { - Name: "BoolInBoolOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "bool", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "bool", - }, - }, - }, - ID: 2424639793, - }, - { - Name: "PointerBoolInBoolOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "bool", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "bool", - IsPointer: true, - }, - }, - }, - ID: 3589606958, - }, - { - Name: "PointerStringInStringOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "string", - IsPointer: true, - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "string", - IsPointer: true, - }, - }, - }, - ID: 229603958, - }, - { - Name: "StructPointerInputErrorOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "Person", - IsPointer: true, - IsStruct: true, - Package: "main", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "error", - }, - }, - }, - ID: 2447692557, - }, - { - Name: "StructInputStructOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "Person", - IsStruct: true, - Package: "main", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "Person", - IsStruct: true, - Package: "main", - }, - }, - }, - ID: 3835643147, - }, - { - Name: "StructPointerInputStructPointerOutput", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "Person", - IsPointer: true, - IsStruct: true, - Package: "main", - }, - }, - }, - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "Person", - IsPointer: true, - IsStruct: true, - Package: "main", - }, - }, - }, - ID: 2943477349, - }, - { - Name: "MapIntInt", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "map", - MapKey: &ParameterType{ - Name: "int", - }, - MapValue: &ParameterType{ - Name: "int", - }, - }, - }, - }, - ID: 2386486356, - }, - { - Name: "PointerMapIntInt", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "map", - IsPointer: true, - MapKey: &ParameterType{ - Name: "int", - }, - MapValue: &ParameterType{ - Name: "int", - }, - }, - }, - }, - ID: 3516977899, - }, - { - Name: "MapIntPointerInt", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "map", - MapKey: &ParameterType{ - Name: "int", - IsPointer: true, - }, - MapValue: &ParameterType{ - Name: "int", - }, - }, - }, - }, - ID: 550413585, - }, - { - Name: "MapIntSliceInt", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "map", - MapKey: &ParameterType{ - Name: "int", - }, - MapValue: &ParameterType{ - Name: "int", - IsSlice: true, - }, - }, - }, - }, - ID: 2900172572, - }, - { - Name: "MapIntSliceIntInMapIntSliceIntOut", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "map", - MapKey: &ParameterType{ - Name: "int", - }, - MapValue: &ParameterType{ - Name: "int", - IsSlice: true, - }, - }, - }, - }, - Outputs: []*Parameter{ - { - Name: "out", - Type: &ParameterType{ - Name: "map", - MapKey: &ParameterType{ - Name: "int", - }, - MapValue: &ParameterType{ - Name: "int", - IsSlice: true, - }, - }, - }, - }, - ID: 881980169, - }, - { - Name: "ArrayInt", - Inputs: []*Parameter{ - { - Name: "in", - Type: &ParameterType{ - Name: "int", - IsSlice: true, - }, - }, - }, - ID: 3862002418, - }, - }, - }, - }, - wantModels: map[string]map[string]*StructDef{ - "main": { - "Person": { - Name: "Person", - Fields: []*Field{ - { - Name: "Name", - Type: &ParameterType{ - Name: "string", - }, - }, - { - Name: "Parent", - Type: &ParameterType{ - Name: "Person", - IsStruct: true, - IsPointer: true, - Package: "main", - }, - }, - { - Name: "Details", - Type: &ParameterType{ - Name: "anon1", - IsStruct: true, - Package: "main", - }, - }, - }, - }, - "anon1": { - Name: "anon1", - Fields: []*Field{ - { - Name: "Age", - Type: &ParameterType{ - Name: "int", - }, - }, - { - Name: "Address", - Type: &ParameterType{ - Name: "anon2", - IsStruct: true, - Package: "main", - }, - }, - }, - }, - "anon2": { - Name: "anon2", - Fields: []*Field{ - { - Name: "Street", - Type: &ParameterType{ - Name: "string", - }, - }, - }, - }, - }, - }, - wantErr: false, - }, - { - name: "should find multiple bound services", - dir: "testdata/struct_literal_multiple", - wantBoundMethods: map[string]map[string][]*BoundMethod{ - "main": { - "GreetService": { - { - Name: "Greet", - DocComment: "", - Inputs: []*Parameter{ - { - Name: "name", - Type: &ParameterType{ - Name: "string", - }, - }, - }, - Outputs: []*Parameter{ - { - Name: "", - Type: &ParameterType{ - Name: "string", - }, - }, - }, - ID: 1411160069, - }, - }, - "OtherService": { - { - Name: "Hello", - ID: 4249972365, - }, - }, - }, - }, - wantErr: false, - }, - { - name: "should find multiple bound services over multiple files", - dir: "testdata/struct_literal_multiple_files", - wantBoundMethods: map[string]map[string][]*BoundMethod{ - "main": { - "GreetService": { - { - Name: "Greet", - DocComment: "", - Inputs: []*Parameter{ - { - Name: "name", - Type: &ParameterType{ - Name: "string", - }, - }, - }, - Outputs: []*Parameter{ - { - Name: "", - Type: &ParameterType{ - Name: "string", - }, - }, - }, - ID: 1411160069, - }, - }, - "OtherService": { - { - Name: "Hello", - ID: 4249972365, - }, - }, - }, - }, - wantErr: false, - }, - { - name: "should find multiple bound services over multiple packages", - dir: "testdata/struct_literal_multiple_other", - wantErr: false, - wantBoundMethods: map[string]map[string][]*BoundMethod{ - "main": { - "GreetService": { - { - Name: "Greet", - DocComment: "Greet does XYZ\n", - Inputs: []*Parameter{ - { - Name: "name", - Type: &ParameterType{ - Name: "string", - }, - }, - }, - Outputs: []*Parameter{ - { - Name: "", - Type: &ParameterType{ - Name: "string", - }, - }, - }, - ID: 1411160069, - }, - { - Name: "NewPerson", - DocComment: "NewPerson creates a new person\n", - Inputs: []*Parameter{ - { - Name: "name", - Type: &ParameterType{ - Name: "string", - }, - }, - }, - Outputs: []*Parameter{ - { - Name: "", - Type: &ParameterType{ - Name: "Person", - IsPointer: true, - IsStruct: true, - Package: "main", - }, - }, - }, - ID: 1661412647, - }, - }, - }, - "github.com/wailsapp/wails/v3/internal/parser/testdata/struct_literal_multiple_other/services": { - "OtherService": { - { - Name: "Yay", - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "Address", - IsStruct: true, - IsPointer: true, - Package: "github.com/wailsapp/wails/v3/internal/parser/testdata/struct_literal_multiple_other/services", - }, - }, - }, - ID: 469445984, - }, - }, - }, - }, - wantModels: map[string]map[string]*StructDef{ - "main": { - "Person": { - Name: "Person", - Fields: []*Field{ - { - Name: "Name", - Type: &ParameterType{ - Name: "string", - }, - }, - { - Name: "Address", - Type: &ParameterType{ - Name: "Address", - IsStruct: true, - IsPointer: true, - Package: "github.com/wailsapp/wails/v3/internal/parser/testdata/struct_literal_multiple_other/services", - }, - }, - }, - }, - }, - "github.com/wailsapp/wails/v3/internal/parser/testdata/struct_literal_multiple_other/services": { - "Address": { - Name: "Address", - Fields: []*Field{ - { - Name: "Street", - Type: &ParameterType{ - Name: "string", - }, - }, - { - Name: "State", - Type: &ParameterType{ - Name: "string", - }, - }, - { - Name: "Country", - Type: &ParameterType{ - Name: "string", - }, - }, - }, - }, - }, - }, - }, - { - name: "should find a bound services using a variable", - dir: "testdata/variable_single", - wantErr: false, - wantBoundMethods: 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", - }, - }, - }, - ID: 1411160069, - }, - }, - }, - }, - }, - { - name: "should find a bound services using a variable from function call", - dir: "testdata/variable_single_from_function", - wantErr: false, - wantBoundMethods: 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", - }, - }, - }, - ID: 1411160069, - }, - }, - }, - }, - }, - { - name: "should find a bound services using a variable from function call in another package", - dir: "testdata/variable_single_from_other_function", - wantErr: false, - wantBoundMethods: map[string]map[string][]*BoundMethod{ - "main": { - "GreetService": { - { - Name: "Greet", - DocComment: "Greet does XYZ\n", - Inputs: []*Parameter{ - { - Name: "name", - Type: &ParameterType{ - Name: "string", - }, - }, - }, - Outputs: []*Parameter{ - { - Name: "", - Type: &ParameterType{ - Name: "string", - }, - }, - }, - ID: 1411160069, - }, - { - Name: "NewPerson", - DocComment: "NewPerson creates a new person\n", - Inputs: []*Parameter{ - { - Name: "name", - Type: &ParameterType{ - Name: "string", - }, - }, - }, - Outputs: []*Parameter{ - { - Name: "", - Type: &ParameterType{ - Name: "Person", - IsPointer: true, - IsStruct: true, - Package: "main", - }, - }, - }, - ID: 1661412647, - }, - }, - }, - "github.com/wailsapp/wails/v3/internal/parser/testdata/variable_single_from_other_function/services": { - "OtherService": { - { - Name: "Yay", - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "Address", - IsStruct: true, - IsPointer: true, - Package: "github.com/wailsapp/wails/v3/internal/parser/testdata/variable_single_from_other_function/services", - }, - }, - }, - ID: 302702907, - }, - }, - }, - }, - wantModels: map[string]map[string]*StructDef{ - "main": { - "Person": { - Name: "Person", - Fields: []*Field{ - { - Name: "Name", - Type: &ParameterType{ - Name: "string", - }, - }, - { - Name: "Address", - Type: &ParameterType{ - Name: "Address", - IsStruct: true, - IsPointer: true, - Package: "github.com/wailsapp/wails/v3/internal/parser/testdata/variable_single_from_other_function/services", - }, - }, - }, - }, - }, - "github.com/wailsapp/wails/v3/internal/parser/testdata/variable_single_from_other_function/services": { - "Address": { - Name: "Address", - Fields: []*Field{ - { - Name: "Street", - Type: &ParameterType{ - Name: "string", - }, - }, - { - Name: "State", - Type: &ParameterType{ - Name: "string", - }, - }, - { - Name: "Country", - Type: &ParameterType{ - Name: "string", - }, - }, - }, - }, - }, - }, - }, - { - name: "should find a bound service returned from a function call", - dir: "testdata/function_single", - wantErr: false, - wantBoundMethods: 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", - }, - }, - }, - ID: 1411160069, - }, - }, - }, - }, - }, - { - name: "should find a bound service returned from a function call in another package", - dir: "testdata/function_from_imported_package", - wantErr: false, - wantBoundMethods: map[string]map[string][]*BoundMethod{ - "main": { - "GreetService": { - { - Name: "Greet", - DocComment: "Greet does XYZ\n", - Inputs: []*Parameter{ - { - Name: "name", - Type: &ParameterType{ - Name: "string", - }, - }, - }, - Outputs: []*Parameter{ - { - Name: "", - Type: &ParameterType{ - Name: "string", - }, - }, - }, - ID: 1411160069, - }, - { - Name: "NewPerson", - DocComment: "NewPerson creates a new person\n", - Inputs: []*Parameter{ - { - Name: "name", - Type: &ParameterType{ - Name: "string", - }, - }, - }, - Outputs: []*Parameter{ - { - Name: "", - Type: &ParameterType{ - Name: "Person", - IsPointer: true, - IsStruct: true, - Package: "main", - }, - }, - }, - ID: 1661412647, - }, - }, - }, - "github.com/wailsapp/wails/v3/internal/parser/testdata/variable_single_from_other_function/services": { - "OtherService": { - { - Name: "Yay", - Outputs: []*Parameter{ - { - Type: &ParameterType{ - Name: "Address", - IsStruct: true, - IsPointer: true, - Package: "github.com/wailsapp/wails/v3/internal/parser/testdata/variable_single_from_other_function/services", - }, - }, - }, - ID: 302702907, - }, - }, - }, - }, - wantModels: map[string]map[string]*StructDef{ - "main": { - "Person": { - Name: "Person", - Fields: []*Field{ - { - Name: "Name", - Type: &ParameterType{ - Name: "string", - }, - }, - { - Name: "Address", - Type: &ParameterType{ - Name: "Address", - IsStruct: true, - IsPointer: true, - Package: "github.com/wailsapp/wails/v3/internal/parser/testdata/variable_single_from_other_function/services", - }, - }, - }, - }, - }, - "github.com/wailsapp/wails/v3/internal/parser/testdata/variable_single_from_other_function/services": { - "Address": { - Name: "Address", - Fields: []*Field{ - { - Name: "Street", - Type: &ParameterType{ - Name: "string", - }, - }, - { - Name: "State", - Type: &ParameterType{ - Name: "string", - }, - }, - { - Name: "Country", - Type: &ParameterType{ - Name: "string", - }, - }, - }, - }, - }, - }, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := ParseProject(tt.dir) - if (err != nil) != tt.wantErr { - t.Errorf("ParseDirectory() error = %v, wantErr %v", err, tt.wantErr) - return - } - if diff := cmp.Diff(tt.wantBoundMethods, got.BoundMethods); diff != "" { - t.Errorf("ParseDirectory() failed:\n" + diff) - } - if diff := cmp.Diff(tt.wantModels, got.Models); diff != "" { - t.Errorf("ParseDirectory() failed:\n" + diff) - } - }) - } - -} - -//func TestGenerateTypeScript(t *testing.T) { -// tests := []struct { -// name string -// dir string -// wantModels string -// wantErr bool -// }{ -// { -// name: "should find single bound service", -// dir: "testdata/struct_literal_single", -// wantModels: `namespace main { -// class GreetService { -// SomeVariable: number; -// } -//} -//`, -// wantErr: false, -// }, -// { -// name: "should find multiple bound services", -// dir: "testdata/struct_literal_multiple", -// wantModels: `namespace main { -// class GreetService { -// SomeVariable: number; -// } -// class OtherService { -// } -//} -//`, -// wantErr: false, -// }, -// { -// name: "should find multiple bound services over multiple files", -// dir: "testdata/struct_literal_multiple_files", -// wantModels: `namespace main { -// class GreetService { -// SomeVariable: number; -// } -// class OtherService { -// } -//} -//`, -// wantErr: false, -// }, -// { -// name: "should find bound services from other packages", -// dir: "../../examples/binding", -// wantModels: `namespace main { -// class localStruct { -// } -//} -//namespace models { -// class Person { -// Name: string; -// } -//} -//namespace services { -// class GreetService { -// SomeVariable: number; -// Parent: models.Person; -// } -//} -//`, -// wantErr: false, -// }, -// } -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// Debug = true -// context, err := ParseDirectory(tt.dir) -// if (err != nil) != tt.wantErr { -// t.Errorf("ParseDirectory() error = %v, wantErr %v", err, tt.wantErr) -// return -// } -// -// ts, err := GenerateModels(context) -// require.NoError(t, err) -// require.Equal(t, tt.wantModels, string(ts)) -// -// }) -// } -//} diff --git a/v3/internal/parser/parser_variable_single_test.go b/v3/internal/parser/parser_variable_single_test.go new file mode 100644 index 00000000..29683b47 --- /dev/null +++ b/v3/internal/parser/parser_variable_single_test.go @@ -0,0 +1,238 @@ +package parser + +import ( + "reflect" + "testing" + + "github.com/google/go-cmp/cmp" +) + +func TestParseVariableSingle(t *testing.T) { + tests := []struct { + name string + dir string + wantBoundMethods map[string]map[string][]*BoundMethod + wantEnums map[string]map[string]*EnumDef + wantModels map[string]map[string]*StructDef + wantTypes map[string]map[string]*TypeDef + wantErr bool + }{ + { + name: "should find a bound services using a variable", + dir: "testdata/variable_single", + wantErr: false, + wantBoundMethods: map[string]map[string][]*BoundMethod{ + "main": { + "GreetService": { + { + Name: "Greet", + DocComment: "Greet someone", + Inputs: []*Parameter{ + { + Name: "name", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + Outputs: []*Parameter{ + { + Name: "", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + ID: 1411160069, + }, + }, + }, + }, + }, + { + name: "should find a bound services using a variable from function call", + dir: "testdata/variable_single_from_function", + wantErr: false, + wantBoundMethods: map[string]map[string][]*BoundMethod{ + "main": { + "GreetService": { + { + Name: "Greet", + DocComment: "Greet someone", + Inputs: []*Parameter{ + { + Name: "name", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + Outputs: []*Parameter{ + { + Name: "", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + ID: 1411160069, + }, + }, + }, + }, + }, + { + name: "should find a bound services using a variable from function call in another package", + dir: "testdata/variable_single_from_other_function", + wantErr: false, + wantBoundMethods: map[string]map[string][]*BoundMethod{ + "main": { + "GreetService": { + { + Name: "Greet", + DocComment: "Greet does XYZ", + Inputs: []*Parameter{ + { + Name: "name", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + Outputs: []*Parameter{ + { + Name: "", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + ID: 1411160069, + }, + { + Name: "NewPerson", + DocComment: "NewPerson creates a new person", + Inputs: []*Parameter{ + { + Name: "name", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + }, + Outputs: []*Parameter{ + { + Name: "", + Type: &ParameterType{ + Package: "main", + Name: "Person", + IsPointer: true, + IsStruct: true, + }, + }, + }, + ID: 1661412647, + }, + }, + }, + "github.com/wailsapp/wails/v3/internal/parser/testdata/variable_single_from_other_function/services": { + "OtherService": { + { + Name: "Yay", + Outputs: []*Parameter{ + { + Type: &ParameterType{ + Name: "Address", + IsStruct: true, + IsPointer: true, + Package: "github.com/wailsapp/wails/v3/internal/parser/testdata/variable_single_from_other_function/services", + }, + }, + }, + ID: 302702907, + }, + }, + }, + }, + wantModels: map[string]map[string]*StructDef{ + "main": { + "Person": { + Name: "Person", + Fields: []*Field{ + { + Name: "Name", + Type: &ParameterType{ + Package: "main", + Name: "string", + }, + }, + { + Name: "Address", + Type: &ParameterType{ + Name: "Address", + IsStruct: true, + IsPointer: true, + Package: "github.com/wailsapp/wails/v3/internal/parser/testdata/variable_single_from_other_function/services", + }, + }, + }, + }, + }, + "github.com/wailsapp/wails/v3/internal/parser/testdata/variable_single_from_other_function/services": { + "Address": { + Name: "Address", + Fields: []*Field{ + { + Name: "Street", + Type: &ParameterType{ + Package: "github.com/wailsapp/wails/v3/internal/parser/testdata/variable_single_from_other_function/services", + Name: "string", + }, + }, + { + Name: "State", + Type: &ParameterType{ + Package: "github.com/wailsapp/wails/v3/internal/parser/testdata/variable_single_from_other_function/services", + Name: "string", + }, + }, + { + Name: "Country", + Type: &ParameterType{ + Package: "github.com/wailsapp/wails/v3/internal/parser/testdata/variable_single_from_other_function/services", + Name: "string", + }, + }, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := ParseProject(tt.dir) + if (err != nil) != tt.wantErr { + t.Errorf("ParseDirectory() error = %v, wantErr %v", err, tt.wantErr) + return + } + if diff := cmp.Diff(tt.wantBoundMethods, got.BoundMethods); diff != "" { + t.Errorf("ParseDirectory() failed:\n" + diff) + } + if !reflect.DeepEqual(tt.wantModels, got.Models) { + t.Errorf("ParseDirectory() failed:\n" + cmp.Diff(tt.wantModels, got.Models)) + } + if diff := cmp.Diff(tt.wantTypes, got.Types); diff != "" { + t.Errorf("ParseDirectory() failed:\n" + diff) + } + }) + } + +} diff --git a/v3/internal/parser/templates/class.ts.tmpl b/v3/internal/parser/templates/class.ts.tmpl deleted file mode 100644 index 886f6b66..00000000 --- a/v3/internal/parser/templates/class.ts.tmpl +++ /dev/null @@ -1,16 +0,0 @@ - export class {{.Name}} { - {{range .Fields}}{{.}} - {{end}} - static createFrom(source: any = {}) { - return new {{.Name}}(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) { - source = JSON.parse(source); - } - - {{range .Fields}}this.{{jsName .}} = source["{{jsName .}}"] - {{end}} - } - } diff --git a/v3/internal/parser/templates/interfaces.ts.tmpl b/v3/internal/parser/templates/interfaces.ts.tmpl new file mode 100644 index 00000000..a65a8a0f --- /dev/null +++ b/v3/internal/parser/templates/interfaces.ts.tmpl @@ -0,0 +1,8 @@ +{{$pkg := .Package}} +export namespace {{.Package}} { + {{range $name, $def := .Models}} + export interface {{$def.Name}} { {{range $def.Fields}} + {{.JSDef $pkg}}{{end}} + } + {{end}} +} diff --git a/v3/internal/parser/templates/model.ts.tmpl b/v3/internal/parser/templates/model.ts.tmpl index 232db747..820ef8a8 100644 --- a/v3/internal/parser/templates/model.ts.tmpl +++ b/v3/internal/parser/templates/model.ts.tmpl @@ -1,21 +1,31 @@ {{$pkg := .Package}} export namespace {{.Package}} { - {{range $name, $def := .Models}} - export class {{$def.Name}} { - {{range $def.Fields}}{{.JSDef $pkg}} + {{range $enumindex, $enumdef := .Enums}} + {{- range $commentindex, $commentdef := .DocComments}} + {{$commentdef -}} + {{- end}} + export enum {{$enumdef.Name}} { + {{- range $constindex, $constdef := .Consts}} + {{- if $constdef.DocComment}} + // {{$constdef.DocComment}} + {{- end}} + {{$constdef.Name}} = {{$constdef.Value}},{{end}} + } + {{- end}} + {{range $name, $def := .Models}} + export class {{$def.Name}} { + {{range $def.Fields}}{{.JSDef $pkg}} + {{end}} + constructor(source: Partial<{{$def.Name}}> = {}) { + const { {{$def.DefaultValueList}} } = source; {{range $def.Fields}} + this.{{.JSName}} = {{.JSName}};{{end}} + } + + static createFrom(source: string | object = {}): {{$def.Name}} { + let parsedSource = typeof source === 'string' ? JSON.parse(source) : source; + return new {{$def.Name}}(parsedSource as Partial<{{$def.Name}}>); + } + + } {{end}} - static createFrom(source: any = {}) { - return new {{$def.Name}}(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) { - source = JSON.parse(source); - } - - {{range $def.Fields}}this.{{.JSName}} = {{.TSBuild $pkg}}; - {{end}} - } - } - {{end}} -} +} \ No newline at end of file diff --git a/v3/internal/parser/testdata/enum/bindings_main.js b/v3/internal/parser/testdata/enum/bindings_main.js new file mode 100644 index 00000000..e00a3076 --- /dev/null +++ b/v3/internal/parser/testdata/enum/bindings_main.js @@ -0,0 +1,29 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +/** + * @typedef {import('./models').main.Title} mainTitle + * @typedef {import('./models').main.Person} mainPerson + */ + +export const GreetService = { + + /** + * GreetService.Greet + * Greet does XYZ + * @param name {string} + * @param title {mainTitle} + * @returns {Promise} + **/ + Greet: function(name, title) { return wails.CallByID(1411160069, ...Array.prototype.slice.call(arguments, 0)); }, + + /** + * GreetService.NewPerson + * NewPerson creates a new person + * @param name {string} + * @returns {Promise} + **/ + NewPerson: function(name) { return wails.CallByID(1661412647, ...Array.prototype.slice.call(arguments, 0)); }, +}; + diff --git a/v3/internal/parser/testdata/enum/main.go b/v3/internal/parser/testdata/enum/main.go new file mode 100644 index 00000000..e4677ec7 --- /dev/null +++ b/v3/internal/parser/testdata/enum/main.go @@ -0,0 +1,58 @@ +package main + +import ( + _ "embed" + "log" + + "github.com/wailsapp/wails/v3/pkg/application" +) + +type Title string + +const ( + // Mister is a title + Mister Title = "Mr" + Miss Title = "Miss" + Ms Title = "Ms" + Mrs Title = "Mrs" + Dr Title = "Dr" +) + +// GreetService is great +type GreetService struct { + SomeVariable int + lowerCase string + target *Person +} + +type Person struct { + Title Title + Name string +} + +// Greet does XYZ +func (*GreetService) Greet(name string, title Title) string { + return "Hello " + string(title) + " " + name +} + +// NewPerson creates a new person +func (*GreetService) NewPerson(name string) *Person { + return &Person{Name: name} +} + +func main() { + app := application.New(application.Options{ + Bind: []interface{}{ + &GreetService{}, + }, + }) + + app.NewWebviewWindow() + + err := app.Run() + + if err != nil { + log.Fatal(err) + } + +} diff --git a/v3/internal/parser/testdata/enum/models.ts b/v3/internal/parser/testdata/enum/models.ts new file mode 100644 index 00000000..a0a73149 --- /dev/null +++ b/v3/internal/parser/testdata/enum/models.ts @@ -0,0 +1,33 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +export namespace main { + + export enum Title { + // Mister is a title + Mister = "Mr", + Miss = "Miss", + Ms = "Ms", + Mrs = "Mrs", + Dr = "Dr", + } + + export class Person { + title: Title; + name: string; + + constructor(source: Partial = {}) { + const { title = null, name = "" } = source; + this.title = title; + this.name = name; + } + + static createFrom(source: string | object = {}): Person { + let parsedSource = typeof source === 'string' ? JSON.parse(source) : source; + return new Person(parsedSource as Partial); + } + + } + +} \ No newline at end of file diff --git a/v3/internal/parser/testdata/enum_from_imported_package/bindings_main.js b/v3/internal/parser/testdata/enum_from_imported_package/bindings_main.js new file mode 100644 index 00000000..1238a0d0 --- /dev/null +++ b/v3/internal/parser/testdata/enum_from_imported_package/bindings_main.js @@ -0,0 +1,30 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +/** + * @typedef {import('./models').main.Person} mainPerson + */ + + +window.go = window.go || {}; +window.go.main = { + GreetService: { + + /** + * GreetService.Greet + * Greet does XYZ + * @param name {string} + * @returns {Promise} + **/ + Greet: function(name) { return wails.CallByID(1411160069, ...Array.prototype.slice.call(arguments, 0)); }, + + /** + * GreetService.NewPerson + * NewPerson creates a new person + * @param name {string} + * @returns {Promise} + **/ + NewPerson: function(name) { return wails.CallByID(1661412647, ...Array.prototype.slice.call(arguments, 0)); }, + }, +}; diff --git a/v3/internal/parser/testdata/enum_from_imported_package/bindings_services.js b/v3/internal/parser/testdata/enum_from_imported_package/bindings_services.js new file mode 100644 index 00000000..f7108c90 --- /dev/null +++ b/v3/internal/parser/testdata/enum_from_imported_package/bindings_services.js @@ -0,0 +1,22 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +/** + * @typedef {import('./models').services.Address} servicesAddress + */ + + +window.go = window.go || {}; +window.go.services = { + OtherService: { + + /** + * OtherService.Yay + * + * + * @returns {Promise} + **/ + Yay: function() { return wails.CallByID(302702907, ...Array.prototype.slice.call(arguments, 0)); }, + }, +}; diff --git a/v3/internal/parser/testdata/enum_from_imported_package/main.go b/v3/internal/parser/testdata/enum_from_imported_package/main.go new file mode 100644 index 00000000..f0d1865e --- /dev/null +++ b/v3/internal/parser/testdata/enum_from_imported_package/main.go @@ -0,0 +1,37 @@ +package main + +import ( + _ "embed" + "github.com/wailsapp/wails/v3/internal/parser/testdata/enum_from_imported_package/services" + "log" + + "github.com/wailsapp/wails/v3/pkg/application" +) + +// GreetService is great +type GreetService struct { + SomeVariable int + lowerCase string +} + +// Greet does XYZ +func (*GreetService) Greet(name string, title services.Title) string { + return "Hello " + title.String() + " " + name +} + +func main() { + app := application.New(application.Options{ + Bind: []interface{}{ + &GreetService{}, + }, + }) + + app.NewWebviewWindow() + + err := app.Run() + + if err != nil { + log.Fatal(err) + } + +} diff --git a/v3/internal/parser/testdata/enum_from_imported_package/models.ts b/v3/internal/parser/testdata/enum_from_imported_package/models.ts new file mode 100644 index 00000000..e9dbb60a --- /dev/null +++ b/v3/internal/parser/testdata/enum_from_imported_package/models.ts @@ -0,0 +1,47 @@ +// @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; + address: services.Address; + + constructor(source: Partial = {}) { + const { name = "", address = null } = source; + this.name = name; + this.address = address; + } + + static createFrom(source: string | object = {}): Person { + let parsedSource = typeof source === 'string' ? JSON.parse(source) : source; + return new Person(parsedSource as Partial); + } + + } + +} + +export namespace services { + + export class Address { + street: string; + state: string; + country: string; + + constructor(source: Partial
= {}) { + const { street = "", state = "", country = "" } = source; + this.street = street; + this.state = state; + this.country = country; + } + + static createFrom(source: string | object = {}): Address { + let parsedSource = typeof source === 'string' ? JSON.parse(source) : source; + return new Address(parsedSource as Partial
); + } + + } + +} diff --git a/v3/internal/parser/testdata/enum_from_imported_package/services/other.go b/v3/internal/parser/testdata/enum_from_imported_package/services/other.go new file mode 100644 index 00000000..5d15f239 --- /dev/null +++ b/v3/internal/parser/testdata/enum_from_imported_package/services/other.go @@ -0,0 +1,16 @@ +package services + +type Title string + +func (t Title) String() string { + return string(t) +} + +const ( + // Mister is a title + Mister Title = "Mr" + Miss Title = "Miss" + Ms Title = "Ms" + Mrs Title = "Mrs" + Dr Title = "Dr" +) diff --git a/v3/internal/parser/testdata/function_from_imported_package/bindings_main.js b/v3/internal/parser/testdata/function_from_imported_package/bindings_main.js index 1238a0d0..ae0db8c5 100644 --- a/v3/internal/parser/testdata/function_from_imported_package/bindings_main.js +++ b/v3/internal/parser/testdata/function_from_imported_package/bindings_main.js @@ -6,15 +6,12 @@ * @typedef {import('./models').main.Person} mainPerson */ - -window.go = window.go || {}; -window.go.main = { - GreetService: { +export const GreetService = { /** * GreetService.Greet * Greet does XYZ - * @param name {string} + * @param name {string} * @returns {Promise} **/ Greet: function(name) { return wails.CallByID(1411160069, ...Array.prototype.slice.call(arguments, 0)); }, @@ -22,9 +19,9 @@ window.go.main = { /** * GreetService.NewPerson * NewPerson creates a new person - * @param name {string} + * @param name {string} * @returns {Promise} **/ NewPerson: function(name) { return wails.CallByID(1661412647, ...Array.prototype.slice.call(arguments, 0)); }, - }, }; + diff --git a/v3/internal/parser/testdata/function_from_imported_package/bindings_services.js b/v3/internal/parser/testdata/function_from_imported_package/bindings_services.js index f7108c90..9b0d9d63 100644 --- a/v3/internal/parser/testdata/function_from_imported_package/bindings_services.js +++ b/v3/internal/parser/testdata/function_from_imported_package/bindings_services.js @@ -6,17 +6,14 @@ * @typedef {import('./models').services.Address} servicesAddress */ - -window.go = window.go || {}; -window.go.services = { - OtherService: { +export const OtherService = { /** * OtherService.Yay * - * + * * @returns {Promise} **/ Yay: function() { return wails.CallByID(302702907, ...Array.prototype.slice.call(arguments, 0)); }, - }, }; + diff --git a/v3/internal/parser/testdata/function_from_imported_package/models.ts b/v3/internal/parser/testdata/function_from_imported_package/models.ts index a6639f8e..c44731c2 100644 --- a/v3/internal/parser/testdata/function_from_imported_package/models.ts +++ b/v3/internal/parser/testdata/function_from_imported_package/models.ts @@ -3,49 +3,46 @@ // This file is automatically generated. DO NOT EDIT export namespace main { - - export class Person { - name: string; - address: services.Address; - static createFrom(source: any = {}) { - return new Person(source); - } + + export class Person { + name: string; + address: services.Address; + + constructor(source: Partial = {}) { + const { name = "", address = null } = source; + this.name = name; + this.address = address; + } - constructor(source: any = {}) { - if ('string' === typeof source) { - source = JSON.parse(source); - } + static createFrom(source: string | object = {}): Person { + let parsedSource = typeof source === 'string' ? JSON.parse(source) : source; + return new Person(parsedSource as Partial); + } - this.name = source['name']; - this.address = services.Address.createFrom(source['address']); - } - } - + } - export namespace services { - - export class Address { - street: string; - state: string; - country: string; - static createFrom(source: any = {}) { - return new Address(source); - } + + export class Address { + street: string; + state: string; + country: string; + + constructor(source: Partial
= {}) { + const { street = "", state = "", country = "" } = source; + this.street = street; + this.state = state; + this.country = country; + } - constructor(source: any = {}) { - if ('string' === typeof source) { - source = JSON.parse(source); - } + static createFrom(source: string | object = {}): Address { + let parsedSource = typeof source === 'string' ? JSON.parse(source) : source; + return new Address(parsedSource as Partial
); + } - this.street = source['street']; - this.state = source['state']; - this.country = source['country']; - } - } - -} + +} \ No newline at end of file diff --git a/v3/internal/parser/testdata/function_single/bindings_main.js b/v3/internal/parser/testdata/function_single/bindings_main.js index 70e74f98..0707d98f 100644 --- a/v3/internal/parser/testdata/function_single/bindings_main.js +++ b/v3/internal/parser/testdata/function_single/bindings_main.js @@ -2,17 +2,14 @@ // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL // This file is automatically generated. DO NOT EDIT - -window.go = window.go || {}; -window.go.main = { - GreetService: { +export const GreetService = { /** * GreetService.Greet * Greet someone - * @param name {string} + * @param name {string} * @returns {Promise} **/ Greet: function(name) { return wails.CallByID(1411160069, ...Array.prototype.slice.call(arguments, 0)); }, - }, }; + diff --git a/v3/internal/parser/testdata/struct_literal_multiple/bindings_main.js b/v3/internal/parser/testdata/struct_literal_multiple/bindings_main.js index a50a35cb..e4ed6e6c 100644 --- a/v3/internal/parser/testdata/struct_literal_multiple/bindings_main.js +++ b/v3/internal/parser/testdata/struct_literal_multiple/bindings_main.js @@ -2,27 +2,25 @@ // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL // This file is automatically generated. DO NOT EDIT - -window.go = window.go || {}; -window.go.main = { - GreetService: { +export const GreetService = { /** * GreetService.Greet * - * @param name {string} + * @param name {string} * @returns {Promise} **/ Greet: function(name) { return wails.CallByID(1411160069, ...Array.prototype.slice.call(arguments, 0)); }, - }, - OtherService: { +}; + +export const OtherService = { /** * OtherService.Hello * - * + * * @returns {Promise} **/ Hello: function() { return wails.CallByID(4249972365, ...Array.prototype.slice.call(arguments, 0)); }, - }, }; + diff --git a/v3/internal/parser/testdata/struct_literal_multiple_files/bindings_main.js b/v3/internal/parser/testdata/struct_literal_multiple_files/bindings_main.js index a50a35cb..e4ed6e6c 100644 --- a/v3/internal/parser/testdata/struct_literal_multiple_files/bindings_main.js +++ b/v3/internal/parser/testdata/struct_literal_multiple_files/bindings_main.js @@ -2,27 +2,25 @@ // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL // This file is automatically generated. DO NOT EDIT - -window.go = window.go || {}; -window.go.main = { - GreetService: { +export const GreetService = { /** * GreetService.Greet * - * @param name {string} + * @param name {string} * @returns {Promise} **/ Greet: function(name) { return wails.CallByID(1411160069, ...Array.prototype.slice.call(arguments, 0)); }, - }, - OtherService: { +}; + +export const OtherService = { /** * OtherService.Hello * - * + * * @returns {Promise} **/ Hello: function() { return wails.CallByID(4249972365, ...Array.prototype.slice.call(arguments, 0)); }, - }, }; + diff --git a/v3/internal/parser/testdata/struct_literal_multiple_other/bindings_main.js b/v3/internal/parser/testdata/struct_literal_multiple_other/bindings_main.js index 1238a0d0..ae0db8c5 100644 --- a/v3/internal/parser/testdata/struct_literal_multiple_other/bindings_main.js +++ b/v3/internal/parser/testdata/struct_literal_multiple_other/bindings_main.js @@ -6,15 +6,12 @@ * @typedef {import('./models').main.Person} mainPerson */ - -window.go = window.go || {}; -window.go.main = { - GreetService: { +export const GreetService = { /** * GreetService.Greet * Greet does XYZ - * @param name {string} + * @param name {string} * @returns {Promise} **/ Greet: function(name) { return wails.CallByID(1411160069, ...Array.prototype.slice.call(arguments, 0)); }, @@ -22,9 +19,9 @@ window.go.main = { /** * GreetService.NewPerson * NewPerson creates a new person - * @param name {string} + * @param name {string} * @returns {Promise} **/ NewPerson: function(name) { return wails.CallByID(1661412647, ...Array.prototype.slice.call(arguments, 0)); }, - }, }; + diff --git a/v3/internal/parser/testdata/struct_literal_multiple_other/bindings_services.js b/v3/internal/parser/testdata/struct_literal_multiple_other/bindings_services.js index ea8a85c4..b9647461 100644 --- a/v3/internal/parser/testdata/struct_literal_multiple_other/bindings_services.js +++ b/v3/internal/parser/testdata/struct_literal_multiple_other/bindings_services.js @@ -6,17 +6,14 @@ * @typedef {import('./models').services.Address} servicesAddress */ - -window.go = window.go || {}; -window.go.services = { - OtherService: { +export const OtherService = { /** * OtherService.Yay * - * + * * @returns {Promise} **/ Yay: function() { return wails.CallByID(469445984, ...Array.prototype.slice.call(arguments, 0)); }, - }, }; + diff --git a/v3/internal/parser/testdata/struct_literal_multiple_other/models.ts b/v3/internal/parser/testdata/struct_literal_multiple_other/models.ts index a6639f8e..c44731c2 100644 --- a/v3/internal/parser/testdata/struct_literal_multiple_other/models.ts +++ b/v3/internal/parser/testdata/struct_literal_multiple_other/models.ts @@ -3,49 +3,46 @@ // This file is automatically generated. DO NOT EDIT export namespace main { - - export class Person { - name: string; - address: services.Address; - static createFrom(source: any = {}) { - return new Person(source); - } + + export class Person { + name: string; + address: services.Address; + + constructor(source: Partial = {}) { + const { name = "", address = null } = source; + this.name = name; + this.address = address; + } - constructor(source: any = {}) { - if ('string' === typeof source) { - source = JSON.parse(source); - } + static createFrom(source: string | object = {}): Person { + let parsedSource = typeof source === 'string' ? JSON.parse(source) : source; + return new Person(parsedSource as Partial); + } - this.name = source['name']; - this.address = services.Address.createFrom(source['address']); - } - } - + } - export namespace services { - - export class Address { - street: string; - state: string; - country: string; - static createFrom(source: any = {}) { - return new Address(source); - } + + export class Address { + street: string; + state: string; + country: string; + + constructor(source: Partial
= {}) { + const { street = "", state = "", country = "" } = source; + this.street = street; + this.state = state; + this.country = country; + } - constructor(source: any = {}) { - if ('string' === typeof source) { - source = JSON.parse(source); - } + static createFrom(source: string | object = {}): Address { + let parsedSource = typeof source === 'string' ? JSON.parse(source) : source; + return new Address(parsedSource as Partial
); + } - this.street = source['street']; - this.state = source['state']; - this.country = source['country']; - } - } - -} + +} \ No newline at end of file diff --git a/v3/internal/parser/testdata/struct_literal_single/bindings_main.js b/v3/internal/parser/testdata/struct_literal_single/bindings_main.js index fd61234e..0cdc9fbe 100644 --- a/v3/internal/parser/testdata/struct_literal_single/bindings_main.js +++ b/v3/internal/parser/testdata/struct_literal_single/bindings_main.js @@ -6,15 +6,12 @@ * @typedef {import('./models').main.Person} mainPerson */ - -window.go = window.go || {}; -window.go.main = { - GreetService: { +export const GreetService = { /** * GreetService.ArrayInt * - * @param _in {number[]} + * @param _in {number[]} * @returns {Promise} **/ ArrayInt: function(_in) { return wails.CallByID(3862002418, ...Array.prototype.slice.call(arguments, 0)); }, @@ -22,7 +19,7 @@ window.go.main = { /** * GreetService.BoolInBoolOut * - * @param _in {boolean} + * @param _in {boolean} * @returns {Promise} **/ BoolInBoolOut: function(_in) { return wails.CallByID(2424639793, ...Array.prototype.slice.call(arguments, 0)); }, @@ -30,7 +27,7 @@ window.go.main = { /** * GreetService.Float32InFloat32Out * - * @param _in {number} + * @param _in {number} * @returns {Promise} **/ Float32InFloat32Out: function(_in) { return wails.CallByID(3132595881, ...Array.prototype.slice.call(arguments, 0)); }, @@ -38,7 +35,7 @@ window.go.main = { /** * GreetService.Float64InFloat64Out * - * @param _in {number} + * @param _in {number} * @returns {Promise} **/ Float64InFloat64Out: function(_in) { return wails.CallByID(2182412247, ...Array.prototype.slice.call(arguments, 0)); }, @@ -46,7 +43,7 @@ window.go.main = { /** * GreetService.Greet * Greet someone - * @param name {string} + * @param name {string} * @returns {Promise} **/ Greet: function(name) { return wails.CallByID(1411160069, ...Array.prototype.slice.call(arguments, 0)); }, @@ -54,7 +51,7 @@ window.go.main = { /** * GreetService.Int16InIntOut * - * @param _in {number} + * @param _in {number} * @returns {Promise} **/ Int16InIntOut: function(_in) { return wails.CallByID(3306292566, ...Array.prototype.slice.call(arguments, 0)); }, @@ -62,7 +59,7 @@ window.go.main = { /** * GreetService.Int16PointerInAndOutput * - * @param _in {number | null} + * @param _in {number | null} * @returns {Promise} **/ Int16PointerInAndOutput: function(_in) { return wails.CallByID(1754277916, ...Array.prototype.slice.call(arguments, 0)); }, @@ -70,7 +67,7 @@ window.go.main = { /** * GreetService.Int32InIntOut * - * @param _in {number} + * @param _in {number} * @returns {Promise} **/ Int32InIntOut: function(_in) { return wails.CallByID(1909469092, ...Array.prototype.slice.call(arguments, 0)); }, @@ -78,7 +75,7 @@ window.go.main = { /** * GreetService.Int32PointerInAndOutput * - * @param _in {number | null} + * @param _in {number | null} * @returns {Promise} **/ Int32PointerInAndOutput: function(_in) { return wails.CallByID(4251088558, ...Array.prototype.slice.call(arguments, 0)); }, @@ -86,7 +83,7 @@ window.go.main = { /** * GreetService.Int64InIntOut * - * @param _in {number} + * @param _in {number} * @returns {Promise} **/ Int64InIntOut: function(_in) { return wails.CallByID(1343888303, ...Array.prototype.slice.call(arguments, 0)); }, @@ -94,7 +91,7 @@ window.go.main = { /** * GreetService.Int64PointerInAndOutput * - * @param _in {number | null} + * @param _in {number | null} * @returns {Promise} **/ Int64PointerInAndOutput: function(_in) { return wails.CallByID(2205561041, ...Array.prototype.slice.call(arguments, 0)); }, @@ -102,7 +99,7 @@ window.go.main = { /** * GreetService.Int8InIntOut * - * @param _in {number} + * @param _in {number} * @returns {Promise} **/ Int8InIntOut: function(_in) { return wails.CallByID(572240879, ...Array.prototype.slice.call(arguments, 0)); }, @@ -110,7 +107,7 @@ window.go.main = { /** * GreetService.Int8PointerInAndOutput * - * @param _in {number | null} + * @param _in {number | null} * @returns {Promise} **/ Int8PointerInAndOutput: function(_in) { return wails.CallByID(2189402897, ...Array.prototype.slice.call(arguments, 0)); }, @@ -118,7 +115,7 @@ window.go.main = { /** * GreetService.IntInIntOut * - * @param _in {number} + * @param _in {number} * @returns {Promise} **/ IntInIntOut: function(_in) { return wails.CallByID(642881729, ...Array.prototype.slice.call(arguments, 0)); }, @@ -126,7 +123,7 @@ window.go.main = { /** * GreetService.IntPointerInAndOutput * - * @param _in {number | null} + * @param _in {number | null} * @returns {Promise} **/ IntPointerInAndOutput: function(_in) { return wails.CallByID(1066151743, ...Array.prototype.slice.call(arguments, 0)); }, @@ -134,7 +131,7 @@ window.go.main = { /** * GreetService.IntPointerInputNamedOutputs * - * @param _in {number | null} + * @param _in {number | null} * @returns {Promise} **/ IntPointerInputNamedOutputs: function(_in) { return wails.CallByID(2718999663, ...Array.prototype.slice.call(arguments, 0)); }, @@ -142,7 +139,7 @@ window.go.main = { /** * GreetService.MapIntInt * - * @param _in {map} + * @param _in {map} * @returns {Promise} **/ MapIntInt: function(_in) { return wails.CallByID(2386486356, ...Array.prototype.slice.call(arguments, 0)); }, @@ -150,7 +147,7 @@ window.go.main = { /** * GreetService.MapIntPointerInt * - * @param _in {map} + * @param _in {map} * @returns {Promise} **/ MapIntPointerInt: function(_in) { return wails.CallByID(550413585, ...Array.prototype.slice.call(arguments, 0)); }, @@ -158,7 +155,7 @@ window.go.main = { /** * GreetService.MapIntSliceInt * - * @param _in {map} + * @param _in {map} * @returns {Promise} **/ MapIntSliceInt: function(_in) { return wails.CallByID(2900172572, ...Array.prototype.slice.call(arguments, 0)); }, @@ -166,7 +163,7 @@ window.go.main = { /** * GreetService.MapIntSliceIntInMapIntSliceIntOut * - * @param _in {map} + * @param _in {map} * @returns {Promise} **/ MapIntSliceIntInMapIntSliceIntOut: function(_in) { return wails.CallByID(881980169, ...Array.prototype.slice.call(arguments, 0)); }, @@ -174,7 +171,7 @@ window.go.main = { /** * GreetService.NoInputsStringOut * - * + * * @returns {Promise} **/ NoInputsStringOut: function() { return wails.CallByID(1075577233, ...Array.prototype.slice.call(arguments, 0)); }, @@ -182,7 +179,7 @@ window.go.main = { /** * GreetService.PointerBoolInBoolOut * - * @param _in {boolean | null} + * @param _in {boolean | null} * @returns {Promise} **/ PointerBoolInBoolOut: function(_in) { return wails.CallByID(3589606958, ...Array.prototype.slice.call(arguments, 0)); }, @@ -190,7 +187,7 @@ window.go.main = { /** * GreetService.PointerFloat32InFloat32Out * - * @param _in {number | null} + * @param _in {number | null} * @returns {Promise} **/ PointerFloat32InFloat32Out: function(_in) { return wails.CallByID(224675106, ...Array.prototype.slice.call(arguments, 0)); }, @@ -198,7 +195,7 @@ window.go.main = { /** * GreetService.PointerFloat64InFloat64Out * - * @param _in {number | null} + * @param _in {number | null} * @returns {Promise} **/ PointerFloat64InFloat64Out: function(_in) { return wails.CallByID(2124953624, ...Array.prototype.slice.call(arguments, 0)); }, @@ -206,7 +203,7 @@ window.go.main = { /** * GreetService.PointerMapIntInt * - * @param _in {map | null} + * @param _in {map | null} * @returns {Promise} **/ PointerMapIntInt: function(_in) { return wails.CallByID(3516977899, ...Array.prototype.slice.call(arguments, 0)); }, @@ -214,7 +211,7 @@ window.go.main = { /** * GreetService.PointerStringInStringOut * - * @param _in {string | null} + * @param _in {string | null} * @returns {Promise} **/ PointerStringInStringOut: function(_in) { return wails.CallByID(229603958, ...Array.prototype.slice.call(arguments, 0)); }, @@ -222,7 +219,7 @@ window.go.main = { /** * GreetService.StringArrayInputNamedOutput * - * @param _in {string[]} + * @param _in {string[]} * @returns {Promise} **/ StringArrayInputNamedOutput: function(_in) { return wails.CallByID(3678582682, ...Array.prototype.slice.call(arguments, 0)); }, @@ -230,7 +227,7 @@ window.go.main = { /** * GreetService.StringArrayInputNamedOutputs * - * @param _in {string[]} + * @param _in {string[]} * @returns {Promise} **/ StringArrayInputNamedOutputs: function(_in) { return wails.CallByID(319259595, ...Array.prototype.slice.call(arguments, 0)); }, @@ -238,7 +235,7 @@ window.go.main = { /** * GreetService.StringArrayInputStringArrayOut * - * @param _in {string[]} + * @param _in {string[]} * @returns {Promise} **/ StringArrayInputStringArrayOut: function(_in) { return wails.CallByID(383995060, ...Array.prototype.slice.call(arguments, 0)); }, @@ -246,7 +243,7 @@ window.go.main = { /** * GreetService.StringArrayInputStringOut * - * @param _in {string[]} + * @param _in {string[]} * @returns {Promise} **/ StringArrayInputStringOut: function(_in) { return wails.CallByID(1091960237, ...Array.prototype.slice.call(arguments, 0)); }, @@ -254,7 +251,7 @@ window.go.main = { /** * GreetService.StructInputStructOutput * - * @param _in {mainPerson} + * @param _in {mainPerson} * @returns {Promise} **/ StructInputStructOutput: function(_in) { return wails.CallByID(3835643147, ...Array.prototype.slice.call(arguments, 0)); }, @@ -262,7 +259,7 @@ window.go.main = { /** * GreetService.StructPointerInputErrorOutput * - * @param _in {mainPerson | null} + * @param _in {mainPerson | null} * @returns {Promise} **/ StructPointerInputErrorOutput: function(_in) { return wails.CallByID(2447692557, ...Array.prototype.slice.call(arguments, 0)); }, @@ -270,7 +267,7 @@ window.go.main = { /** * GreetService.StructPointerInputStructPointerOutput * - * @param _in {mainPerson | null} + * @param _in {mainPerson | null} * @returns {Promise} **/ StructPointerInputStructPointerOutput: function(_in) { return wails.CallByID(2943477349, ...Array.prototype.slice.call(arguments, 0)); }, @@ -278,7 +275,7 @@ window.go.main = { /** * GreetService.UInt16InUIntOut * - * @param _in {number} + * @param _in {number} * @returns {Promise} **/ UInt16InUIntOut: function(_in) { return wails.CallByID(3401034892, ...Array.prototype.slice.call(arguments, 0)); }, @@ -286,7 +283,7 @@ window.go.main = { /** * GreetService.UInt16PointerInAndOutput * - * @param _in {number | null} + * @param _in {number | null} * @returns {Promise} **/ UInt16PointerInAndOutput: function(_in) { return wails.CallByID(1236957573, ...Array.prototype.slice.call(arguments, 0)); }, @@ -294,7 +291,7 @@ window.go.main = { /** * GreetService.UInt32InUIntOut * - * @param _in {number} + * @param _in {number} * @returns {Promise} **/ UInt32InUIntOut: function(_in) { return wails.CallByID(1160383782, ...Array.prototype.slice.call(arguments, 0)); }, @@ -302,7 +299,7 @@ window.go.main = { /** * GreetService.UInt32PointerInAndOutput * - * @param _in {number | null} + * @param _in {number | null} * @returns {Promise} **/ UInt32PointerInAndOutput: function(_in) { return wails.CallByID(1739300671, ...Array.prototype.slice.call(arguments, 0)); }, @@ -310,7 +307,7 @@ window.go.main = { /** * GreetService.UInt64InUIntOut * - * @param _in {number} + * @param _in {number} * @returns {Promise} **/ UInt64InUIntOut: function(_in) { return wails.CallByID(793803239, ...Array.prototype.slice.call(arguments, 0)); }, @@ -318,7 +315,7 @@ window.go.main = { /** * GreetService.UInt64PointerInAndOutput * - * @param _in {number | null} + * @param _in {number | null} * @returns {Promise} **/ UInt64PointerInAndOutput: function(_in) { return wails.CallByID(1403757716, ...Array.prototype.slice.call(arguments, 0)); }, @@ -326,7 +323,7 @@ window.go.main = { /** * GreetService.UInt8InUIntOut * - * @param _in {number} + * @param _in {number} * @returns {Promise} **/ UInt8InUIntOut: function(_in) { return wails.CallByID(2988345717, ...Array.prototype.slice.call(arguments, 0)); }, @@ -334,7 +331,7 @@ window.go.main = { /** * GreetService.UInt8PointerInAndOutput * - * @param _in {number | null} + * @param _in {number | null} * @returns {Promise} **/ UInt8PointerInAndOutput: function(_in) { return wails.CallByID(518250834, ...Array.prototype.slice.call(arguments, 0)); }, @@ -342,7 +339,7 @@ window.go.main = { /** * GreetService.UIntInUIntOut * - * @param _in {number} + * @param _in {number} * @returns {Promise} **/ UIntInUIntOut: function(_in) { return wails.CallByID(2836661285, ...Array.prototype.slice.call(arguments, 0)); }, @@ -350,9 +347,9 @@ window.go.main = { /** * GreetService.UIntPointerInAndOutput * - * @param _in {number | null} + * @param _in {number | null} * @returns {Promise} **/ UIntPointerInAndOutput: function(_in) { return wails.CallByID(1367187362, ...Array.prototype.slice.call(arguments, 0)); }, - }, }; + diff --git a/v3/internal/parser/testdata/struct_literal_single/models.ts b/v3/internal/parser/testdata/struct_literal_single/models.ts index 91bab56a..1244c233 100644 --- a/v3/internal/parser/testdata/struct_literal_single/models.ts +++ b/v3/internal/parser/testdata/struct_literal_single/models.ts @@ -3,62 +3,57 @@ // This file is automatically generated. DO NOT EDIT export namespace main { - - export class Person { - name: string; - parent: Person; - details: anon1; - static createFrom(source: any = {}) { - return new Person(source); - } - - constructor(source: any = {}) { - if ('string' === typeof source) { - source = JSON.parse(source); - } - - this.name = source['name']; - this.parent = Person.createFrom(source['parent']); - this.details = anon1.createFrom(source['details']); - - } - } - - export class anon1 { - age: number; - address: anon2; - static createFrom(source: any = {}) { - return new anon1(source); - } + export class Person { + name: string; + parent: Person; + details: anon1; + + constructor(source: Partial = {}) { + const { name = "", parent = null, details = null } = source; + this.name = name; + this.parent = parent; + this.details = details; + } - constructor(source: any = {}) { - if ('string' === typeof source) { - source = JSON.parse(source); - } + static createFrom(source: string | object = {}): Person { + let parsedSource = typeof source === 'string' ? JSON.parse(source) : source; + return new Person(parsedSource as Partial); + } - this.age = source['age']; - this.address = anon2.createFrom(source['address']); - } - } - - export class anon2 { - street: string; - static createFrom(source: any = {}) { - return new anon2(source); - } + export class anon1 { + age: number; + address: anon2; + + constructor(source: Partial = {}) { + const { age = 0, address = null } = source; + this.age = age; + this.address = address; + } - constructor(source: any = {}) { - if ('string' === typeof source) { - source = JSON.parse(source); - } + static createFrom(source: string | object = {}): anon1 { + let parsedSource = typeof source === 'string' ? JSON.parse(source) : source; + return new anon1(parsedSource as Partial); + } - this.street = source['street']; - } - } - -} + + export class anon2 { + street: string; + + constructor(source: Partial = {}) { + const { street = "" } = source; + this.street = street; + } + + static createFrom(source: string | object = {}): anon2 { + let parsedSource = typeof source === 'string' ? JSON.parse(source) : source; + return new anon2(parsedSource as Partial); + } + + } + +} \ No newline at end of file diff --git a/v3/internal/parser/testdata/variable_single/bindings_main.js b/v3/internal/parser/testdata/variable_single/bindings_main.js index 70e74f98..0707d98f 100644 --- a/v3/internal/parser/testdata/variable_single/bindings_main.js +++ b/v3/internal/parser/testdata/variable_single/bindings_main.js @@ -2,17 +2,14 @@ // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL // This file is automatically generated. DO NOT EDIT - -window.go = window.go || {}; -window.go.main = { - GreetService: { +export const GreetService = { /** * GreetService.Greet * Greet someone - * @param name {string} + * @param name {string} * @returns {Promise} **/ Greet: function(name) { return wails.CallByID(1411160069, ...Array.prototype.slice.call(arguments, 0)); }, - }, }; + diff --git a/v3/internal/parser/testdata/variable_single_from_function/bindings_main.js b/v3/internal/parser/testdata/variable_single_from_function/bindings_main.js index 70e74f98..0707d98f 100644 --- a/v3/internal/parser/testdata/variable_single_from_function/bindings_main.js +++ b/v3/internal/parser/testdata/variable_single_from_function/bindings_main.js @@ -2,17 +2,14 @@ // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL // This file is automatically generated. DO NOT EDIT - -window.go = window.go || {}; -window.go.main = { - GreetService: { +export const GreetService = { /** * GreetService.Greet * Greet someone - * @param name {string} + * @param name {string} * @returns {Promise} **/ Greet: function(name) { return wails.CallByID(1411160069, ...Array.prototype.slice.call(arguments, 0)); }, - }, }; + diff --git a/v3/internal/parser/testdata/variable_single_from_other_function/bindings_main.js b/v3/internal/parser/testdata/variable_single_from_other_function/bindings_main.js index 1238a0d0..ae0db8c5 100644 --- a/v3/internal/parser/testdata/variable_single_from_other_function/bindings_main.js +++ b/v3/internal/parser/testdata/variable_single_from_other_function/bindings_main.js @@ -6,15 +6,12 @@ * @typedef {import('./models').main.Person} mainPerson */ - -window.go = window.go || {}; -window.go.main = { - GreetService: { +export const GreetService = { /** * GreetService.Greet * Greet does XYZ - * @param name {string} + * @param name {string} * @returns {Promise} **/ Greet: function(name) { return wails.CallByID(1411160069, ...Array.prototype.slice.call(arguments, 0)); }, @@ -22,9 +19,9 @@ window.go.main = { /** * GreetService.NewPerson * NewPerson creates a new person - * @param name {string} + * @param name {string} * @returns {Promise} **/ NewPerson: function(name) { return wails.CallByID(1661412647, ...Array.prototype.slice.call(arguments, 0)); }, - }, }; + diff --git a/v3/internal/parser/testdata/variable_single_from_other_function/bindings_services.js b/v3/internal/parser/testdata/variable_single_from_other_function/bindings_services.js index f7108c90..9b0d9d63 100644 --- a/v3/internal/parser/testdata/variable_single_from_other_function/bindings_services.js +++ b/v3/internal/parser/testdata/variable_single_from_other_function/bindings_services.js @@ -6,17 +6,14 @@ * @typedef {import('./models').services.Address} servicesAddress */ - -window.go = window.go || {}; -window.go.services = { - OtherService: { +export const OtherService = { /** * OtherService.Yay * - * + * * @returns {Promise} **/ Yay: function() { return wails.CallByID(302702907, ...Array.prototype.slice.call(arguments, 0)); }, - }, }; + diff --git a/v3/internal/parser/testdata/variable_single_from_other_function/models.ts b/v3/internal/parser/testdata/variable_single_from_other_function/models.ts index a6639f8e..c44731c2 100644 --- a/v3/internal/parser/testdata/variable_single_from_other_function/models.ts +++ b/v3/internal/parser/testdata/variable_single_from_other_function/models.ts @@ -3,49 +3,46 @@ // This file is automatically generated. DO NOT EDIT export namespace main { - - export class Person { - name: string; - address: services.Address; - static createFrom(source: any = {}) { - return new Person(source); - } + + export class Person { + name: string; + address: services.Address; + + constructor(source: Partial = {}) { + const { name = "", address = null } = source; + this.name = name; + this.address = address; + } - constructor(source: any = {}) { - if ('string' === typeof source) { - source = JSON.parse(source); - } + static createFrom(source: string | object = {}): Person { + let parsedSource = typeof source === 'string' ? JSON.parse(source) : source; + return new Person(parsedSource as Partial); + } - this.name = source['name']; - this.address = services.Address.createFrom(source['address']); - } - } - + } - export namespace services { - - export class Address { - street: string; - state: string; - country: string; - static createFrom(source: any = {}) { - return new Address(source); - } + + export class Address { + street: string; + state: string; + country: string; + + constructor(source: Partial
= {}) { + const { street = "", state = "", country = "" } = source; + this.street = street; + this.state = state; + this.country = country; + } - constructor(source: any = {}) { - if ('string' === typeof source) { - source = JSON.parse(source); - } + static createFrom(source: string | object = {}): Address { + let parsedSource = typeof source === 'string' ? JSON.parse(source) : source; + return new Address(parsedSource as Partial
); + } - this.street = source['street']; - this.state = source['state']; - this.country = source['country']; - } - } - -} + +} \ No newline at end of file diff --git a/v3/internal/templates/_common/Taskfile.tmpl.yml b/v3/internal/templates/_common/Taskfile.tmpl.yml index aa9c14f5..97be607b 100644 --- a/v3/internal/templates/_common/Taskfile.tmpl.yml +++ b/v3/internal/templates/_common/Taskfile.tmpl.yml @@ -412,8 +412,8 @@ tasks: dev: summary: Runs the application in development mode preconditions: - - sh: wails3 tool checkport -u {{ "\"$WAILS_DEVSERVER_URL\"" }} - msg: "Looks like the devserver isn't available. Please ensure you have run `wails3 task dev:frontend` in another terminal." + - sh: wails3 tool checkport -u {{ "\"$FRONTEND_DEVSERVER_URL\"" }} + msg: 'Cannot connect to frontend dev server ({{ "$FRONTEND_DEVSERVER_URL" }}). Please ensure you have run `wails3 dev:frontend` in another terminal.' cmds: - wails3 tool watcher -path {{ "{{.PATH}}" }} -preexec {{ "\"{{.PREEXEC}}\""}} {{ "{{.PREWAIT}}" }} -postexec {{ "\"{{.POSTEXEC}}\"" }} -ignorefiles {{ "{{.IGNOREFILES}}" }} -ignoredirs {{ "{{.IGNOREDIRS}}" }} -ignoreextensions {{ "{{.IGNOREEXTENSIONS}}" }} -exec {{ "\"{{.EXEC}}\"" }} -debounce {{ "{{.DEBOUNCE}}" }} vars: @@ -423,12 +423,12 @@ tasks: EXEC: 'wails3 task run' POSTEXEC: '' IGNOREFILES: 'Taskfile.yml' - IGNOREDIRS: '.git,frontend' + IGNOREDIRS: '.git,frontend,.idea,.vscode,bin' IGNOREEXTENSIONS: '.exe,.syso' DEBOUNCE: 1000 env: # This is the default vite dev server port - WAILS_DEVSERVER_URL: 'http://localhost:5173' + FRONTEND_DEVSERVER_URL: 'http://localhost:5173' dev:reload: summary: Reloads the application diff --git a/v3/internal/templates/templates_test.go b/v3/internal/templates/templates_test.go deleted file mode 100644 index 4e68036e..00000000 --- a/v3/internal/templates/templates_test.go +++ /dev/null @@ -1,44 +0,0 @@ -package templates - -import ( - "os" - "path/filepath" - "testing" - - "github.com/wailsapp/wails/v3/internal/flags" -) - -func TestInstall(t *testing.T) { - - tests := []struct { - name string - options *flags.Init - wantErr bool - }{ - { - name: "should install template", - options: &flags.Init{ - ProjectName: "test", - TemplateName: "svelte", - Quiet: false, - }, - wantErr: false, - }, - } - for _, tt := range tests { - // Remove test directory if it exists - if _, err := os.Stat(tt.options.ProjectName); err == nil { - _ = os.RemoveAll(tt.options.ProjectName) - } - t.Run(tt.name, func(t *testing.T) { - if err := Install(tt.options); (err != nil) != tt.wantErr { - t.Errorf("Install() error = %v, wantErr %v", err, tt.wantErr) - } - }) - t.Cleanup(func() { - path, _ := os.Getwd() - _ = os.RemoveAll(filepath.Join(path, "..", tt.options.ProjectName)) - }) - } - -}