From cdf4bdd2bab97a411c3da3c2eb715e74ee6b5b8a Mon Sep 17 00:00:00 2001 From: Lea Anthony Date: Wed, 20 Dec 2023 08:06:35 +1100 Subject: [PATCH] Support generating enums from imported package --- v3/internal/parser/bindings_test.go | 3 +- v3/internal/parser/models.go | 5 +- v3/internal/parser/models_test.go | 12 +++++ v3/internal/parser/parser.go | 54 ++++++++++++++++++- .../bindings_main.js | 6 ++- .../bindings_main.name.js | 6 ++- .../bindings_services.js | 22 -------- .../enum_from_imported_package/models.js | 17 ++++++ .../enum_from_imported_package/models.ts | 47 +++------------- 9 files changed, 105 insertions(+), 67 deletions(-) delete mode 100644 v3/internal/parser/testdata/enum_from_imported_package/bindings_services.js create mode 100644 v3/internal/parser/testdata/enum_from_imported_package/models.js diff --git a/v3/internal/parser/bindings_test.go b/v3/internal/parser/bindings_test.go index ac2be3987..89858adec 100644 --- a/v3/internal/parser/bindings_test.go +++ b/v3/internal/parser/bindings_test.go @@ -46,8 +46,7 @@ func TestGenerateBindings(t *testing.T) { { "testdata/enum_from_imported_package", map[string]string{ - "main": getFile("testdata/enum_from_imported_package/bindings_main.js"), - "services": getFile("testdata/enum_from_imported_package/bindings_services.js"), + "main": getFile("testdata/enum_from_imported_package/bindings_main.js"), }, true, }, diff --git a/v3/internal/parser/models.go b/v3/internal/parser/models.go index f6107f162..e0e3cf419 100644 --- a/v3/internal/parser/models.go +++ b/v3/internal/parser/models.go @@ -58,7 +58,7 @@ func pkgAlias(fullPkg string) string { } func GenerateModels(models map[packagePath]map[structName]*StructDef, enums map[packagePath]map[string]*TypeDef, options *flags.GenerateBindingsOptions) (string, error) { - if models == nil { + if models == nil && enums == nil { return "", nil } @@ -71,6 +71,9 @@ func GenerateModels(models map[packagePath]map[structName]*StructDef, enums map[ for pkg := range models { keys = append(keys, pkg) } + for pkg := range enums { + keys = append(keys, pkg) + } sort.Slice(keys, func(i, j int) bool { return pkgAlias(keys[i]) < pkgAlias(keys[j]) diff --git a/v3/internal/parser/models_test.go b/v3/internal/parser/models_test.go index db87f299f..0e70b57f4 100644 --- a/v3/internal/parser/models_test.go +++ b/v3/internal/parser/models_test.go @@ -99,6 +99,18 @@ func TestGenerateModels(t *testing.T) { dir: "testdata/enum", want: getFile("testdata/enum/models.js"), }, + { + name: "enum from imported package", + dir: "testdata/enum_from_imported_package", + want: getFile("testdata/enum_from_imported_package/models.ts"), + useTypescript: true, + }, + { + name: "enum from imported package", + dir: "testdata/enum_from_imported_package", + want: getFile("testdata/enum_from_imported_package/models.js"), + useTypescript: false, + }, { name: "enum interface", dir: "testdata/enum-interface", diff --git a/v3/internal/parser/parser.go b/v3/internal/parser/parser.go index 0c276d03e..044a24d75 100644 --- a/v3/internal/parser/parser.go +++ b/v3/internal/parser/parser.go @@ -403,6 +403,7 @@ func (p *Project) parseDirectory(dir string) (map[string]*ParsedPackage, error) StructCache: make(map[structName]*StructDef), TypeCache: make(map[string]*TypeDef), } + p.parseTypes(map[string]*ParsedPackage{packageName: parsedPackage}) p.packageCache[packageName] = parsedPackage result[packageName] = parsedPackage } @@ -413,6 +414,8 @@ func (p *Project) findApplicationNewCalls(pkgs map[string]*ParsedPackage) (err e var callFound bool + p.parseTypes(pkgs) + for _, pkg := range pkgs { thisPackage := pkg.Pkg // Iterate through the package's files @@ -701,6 +704,14 @@ func (p *Project) parseParameterType(field *ast.Field, pkg *ParsedPackage) *Para log.Fatal(err) } result.IsStruct = p.getStructDef(t.Sel.Name, extPackage) + if !result.IsStruct { + // Check if it's a type alias + typeDef, ok := extPackage.TypeCache[t.Sel.Name] + if ok { + typeDef.ShouldGenerate = true + result.IsEnum = true + } + } result.Package = extPackage.Path case *ast.ArrayType: result.IsSlice = true @@ -814,8 +825,13 @@ func (p *Project) getParsedPackageFromName(packageName string, currentPackage *P Path: path, Dir: dir, StructCache: make(map[string]*StructDef), + TypeCache: make(map[string]*TypeDef), } p.packageCache[path] = result + + // Parse types + p.parseTypes(map[string]*ParsedPackage{path: result}) + return result, nil } } @@ -832,7 +848,7 @@ func getPackageDir(importPath string) (string, error) { } func (p *Project) getPackageFromPath(packagedir string, packagepath string) (*ast.Package, error) { - impPkg, err := parser.ParseDir(token.NewFileSet(), packagedir, nil, parser.AllErrors) + impPkg, err := parser.ParseDir(token.NewFileSet(), packagedir, nil, parser.AllErrors|parser.ParseComments) if err != nil { return nil, err } @@ -1074,6 +1090,42 @@ func (p *Project) RelativePackageDir(path string) string { return strings.TrimPrefix(path, p.Path) } +func (p *Project) parseTypes(pkgs map[string]*ParsedPackage) { + for _, pkg := range pkgs { + thisPackage := pkg.Pkg + // Iterate through the package's files + 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 + + } + + return true + }) + } + p.addTypes(pkg.Path, pkg.TypeCache) + } +} + func getTypeString(expr ast.Expr) string { switch t := expr.(type) { case *ast.Ident: 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 index 2e7716564..489f40012 100644 --- a/v3/internal/parser/testdata/enum_from_imported_package/bindings_main.js +++ b/v3/internal/parser/testdata/enum_from_imported_package/bindings_main.js @@ -2,13 +2,17 @@ // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL // This file is automatically generated. DO NOT EDIT +/** + * @typedef {import('./models').services.Title} servicesTitle + */ + export const GreetService = { /** * GreetService.Greet * Greet does XYZ * @param name {string} - * @param title {Title} + * @param title {servicesTitle} * @returns {Promise} **/ Greet: function(name, title) { return wails.CallByID(1411160069, ...Array.prototype.slice.call(arguments, 0)); }, diff --git a/v3/internal/parser/testdata/enum_from_imported_package/bindings_main.name.js b/v3/internal/parser/testdata/enum_from_imported_package/bindings_main.name.js index bf979a24c..82c895cc7 100644 --- a/v3/internal/parser/testdata/enum_from_imported_package/bindings_main.name.js +++ b/v3/internal/parser/testdata/enum_from_imported_package/bindings_main.name.js @@ -2,13 +2,17 @@ // Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL // This file is automatically generated. DO NOT EDIT +/** + * @typedef {import('./models').services.Title} servicesTitle + */ + export const GreetService = { /** * GreetService.Greet * Greet does XYZ * @param name {string} - * @param title {Title} + * @param title {servicesTitle} * @returns {Promise} **/ Greet: function(name, title) { return wails.CallByName("main.GreetService.Greet", ...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 deleted file mode 100644 index f7108c907..000000000 --- a/v3/internal/parser/testdata/enum_from_imported_package/bindings_services.js +++ /dev/null @@ -1,22 +0,0 @@ -// @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/models.js b/v3/internal/parser/testdata/enum_from_imported_package/models.js new file mode 100644 index 000000000..1dd20f0ff --- /dev/null +++ b/v3/internal/parser/testdata/enum_from_imported_package/models.js @@ -0,0 +1,17 @@ +// @ts-check +// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL +// This file is automatically generated. DO NOT EDIT + +// Defining the services namespace +export const services = {}; + +// Simulating the enum with an object +services.Title = { + // Mister is a title + Mister: "Mr", + Miss: "Miss", + Ms: "Ms", + Mrs: "Mrs", + Dr: "Dr", +}; + diff --git a/v3/internal/parser/testdata/enum_from_imported_package/models.ts b/v3/internal/parser/testdata/enum_from_imported_package/models.ts index e9dbb60a1..79cee99b4 100644 --- a/v3/internal/parser/testdata/enum_from_imported_package/models.ts +++ b/v3/internal/parser/testdata/enum_from_imported_package/models.ts @@ -2,46 +2,15 @@ // 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
); - } - + export enum Title { + // Mister is a title + Mister = "Mr", + Miss = "Miss", + Ms = "Ms", + Mrs = "Mrs", + Dr = "Dr", } -} +} \ No newline at end of file