From 69a1be6d3b82e813770adaca4c07bdd8be228fcd Mon Sep 17 00:00:00 2001 From: 0xbuidl <74317911+0x-buidl@users.noreply.github.com> Date: Thu, 17 Aug 2023 05:31:56 -0400 Subject: [PATCH 1/2] fix: include struct pointer inheritance --- README.md | 26 +++++++++++++++++++++++--- examples/inheritance/index.ts | 2 +- examples/inheritance/inheritance.go | 22 ++++++++++++---------- tygo/write_toplevel.go | 17 +++++++++++++---- 4 files changed, 49 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index c012d17..d9e7d36 100644 --- a/README.md +++ b/README.md @@ -243,7 +243,9 @@ export interface Cat { ## Inheritance -Tygo supports interface inheritance. To extend an `inlined` struct, use the tag `tstype:,extends` on struct fields you wish to extend. Only `struct` types can be extended. +Tygo supports interface inheritance. To extend an `inlined` struct, use the tag `tstype:",extends"` on struct fields you wish to extend. Only `struct` types can be extended. + +Struct pointers are optionally extended using `Partial`. To mark these structs as required, use the tag `tstype:",extends,required"`. Example usage [here](examples/inheritance) @@ -259,9 +261,14 @@ type Base2[T string | int] struct { ID T `json:"id"` } +type OptionalPtr struct { + Field string `json:"field"` +} + type Other[T int] struct { - Base ` tstype:",extends"` + *Base ` tstype:",extends,required"` Base2[T] ` tstype:",extends"` + *OptionalPtr ` tstype:",extends"` external.AnotherStruct ` tstype:",extends"` OtherValue string ` json:"other_value"` } @@ -269,9 +276,22 @@ type Other[T int] struct { ```typescript // Typescript output +export interface Base { + name: string; +} + +export interface Base2 { + id: T; +} + +export interface OptionalPtr { + field: string; +} + export interface Other extends Base, Base2, + Partial, external.AnotherStruct { other_value: string; } @@ -330,7 +350,7 @@ packages: // Golang input type Foo struct { TaggedField string `yaml:"custom_field_name_in_yaml"` - UntaggedField string + UntaggedField string } ``` diff --git a/examples/inheritance/index.ts b/examples/inheritance/index.ts index fcf1e6e..b893cf7 100644 --- a/examples/inheritance/index.ts +++ b/examples/inheritance/index.ts @@ -14,7 +14,7 @@ export interface Base3 { class: T; level: X; } -export interface Other extends Base, Base2, Base3, bookapp.Book, bookapp.TextBook { +export interface Other extends Base, Base2, Partial>, bookapp.Book, bookapp.TextBook { otherWithBase: Base; otherWithBase2: Base2; otherValue: string; diff --git a/examples/inheritance/inheritance.go b/examples/inheritance/inheritance.go index d83dcc5..86b99f3 100644 --- a/examples/inheritance/inheritance.go +++ b/examples/inheritance/inheritance.go @@ -1,6 +1,8 @@ package inheritance -import bookapp "github.com/gzuidhof/tygo/examples/bookstore" +import ( + bookapp "github.com/gzuidhof/tygo/examples/bookstore" +) type Base struct { Name string `json:"name"` @@ -16,13 +18,13 @@ type Base3[T string, X int] struct { } type Other[T int, X string] struct { - Base `tstype:",extends"` - Base2[T] `tstype:",extends"` - Base3[X, T] `tstype:",extends"` - OtherWithBase Base ` json:"otherWithBase"` - OtherWithBase2 Base2[X] ` json:"otherWithBase2"` - OtherValue string ` json:"otherValue"` - Author bookapp.AuthorWithInheritance[T] `tstype:"bookapp.AuthorWithInheritance" json:"author"` - bookapp.Book `tstype:",extends"` - bookapp.TextBook[T] `tstype:",extends"` + *Base `tstype:",extends,required"` + Base2[T] `tstype:",extends"` + *Base3[X, T] `tstype:",extends"` + OtherWithBase Base ` json:"otherWithBase"` + OtherWithBase2 Base2[X] ` json:"otherWithBase2"` + OtherValue string ` json:"otherValue"` + Author bookapp.AuthorWithInheritance[T] `tstype:"bookapp.AuthorWithInheritance" json:"author"` + bookapp.Book `tstype:",extends"` + *bookapp.TextBook[T] `tstype:",extends,required"` } diff --git a/tygo/write_toplevel.go b/tygo/write_toplevel.go index 7d73a81..130e536 100644 --- a/tygo/write_toplevel.go +++ b/tygo/write_toplevel.go @@ -139,7 +139,7 @@ func (g *PackageGenerator) writeTypeInheritanceSpec(s *strings.Builder, fields [ continue } - name, valid := getInheritedType(f.Type) + name, valid := getInheritedType(f.Type, tstypeTag) if valid { inheritances = append(inheritances, name) } @@ -231,7 +231,7 @@ func (g *PackageGenerator) writeValueSpec( } } -func getInheritedType(f ast.Expr) (name string, valid bool) { +func getInheritedType(f ast.Expr, tag *structtag.Tag) (name string, valid bool) { switch ft := f.(type) { case *ast.Ident: if ft.Obj != nil && ft.Obj.Decl != nil { @@ -244,14 +244,14 @@ func getInheritedType(f ast.Expr) (name string, valid bool) { } } case *ast.IndexExpr: - name, valid = getInheritedType(ft.X) + name, valid = getInheritedType(ft.X, tag) if valid { generic := getIdent(ft.Index.(*ast.Ident).Name) name += fmt.Sprintf("<%s>", generic) break } case *ast.IndexListExpr: - name, valid = getInheritedType(ft.X) + name, valid = getInheritedType(ft.X, tag) if valid { generic := "" for _, index := range ft.Indices { @@ -263,6 +263,15 @@ func getInheritedType(f ast.Expr) (name string, valid bool) { case *ast.SelectorExpr: valid = ft.Sel.IsExported() name = fmt.Sprintf("%s.%s", ft.X, ft.Sel) + case *ast.StarExpr: + name, valid = getInheritedType(ft.X, tag) + if valid { + // If the type is not required, mark as optional inheritance + if !tag.HasOption("required") { + name = fmt.Sprintf("Partial<%s>", name) + } + return name, valid + } } return From 3416e9c8f6d41590542d2b9cb2c66cd5d18c4183 Mon Sep 17 00:00:00 2001 From: 0xbuidl <74317911+0x-buidl@users.noreply.github.com> Date: Fri, 18 Aug 2023 08:21:59 -0400 Subject: [PATCH 2/2] chore: cleanups --- README.md | 2 ++ examples/inheritance/inheritance.go | 18 +++++++++--------- tygo/write_toplevel.go | 4 ---- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index d9e7d36..eb9e586 100644 --- a/README.md +++ b/README.md @@ -247,6 +247,8 @@ Tygo supports interface inheritance. To extend an `inlined` struct, use the tag Struct pointers are optionally extended using `Partial`. To mark these structs as required, use the tag `tstype:",extends,required"`. +Named `struct fields` can also be extended. + Example usage [here](examples/inheritance) ```go diff --git a/examples/inheritance/inheritance.go b/examples/inheritance/inheritance.go index 86b99f3..3d46ba7 100644 --- a/examples/inheritance/inheritance.go +++ b/examples/inheritance/inheritance.go @@ -18,13 +18,13 @@ type Base3[T string, X int] struct { } type Other[T int, X string] struct { - *Base `tstype:",extends,required"` - Base2[T] `tstype:",extends"` - *Base3[X, T] `tstype:",extends"` - OtherWithBase Base ` json:"otherWithBase"` - OtherWithBase2 Base2[X] ` json:"otherWithBase2"` - OtherValue string ` json:"otherValue"` - Author bookapp.AuthorWithInheritance[T] `tstype:"bookapp.AuthorWithInheritance" json:"author"` - bookapp.Book `tstype:",extends"` - *bookapp.TextBook[T] `tstype:",extends,required"` + *Base `tstype:",extends,required"` + Base2[T] `tstype:",extends"` + *Base3[X, T] `tstype:",extends"` + OtherWithBase Base ` json:"otherWithBase"` + OtherWithBase2 Base2[X] ` json:"otherWithBase2"` + OtherValue string ` json:"otherValue"` + Author bookapp.AuthorWithInheritance[T] `tstype:"bookapp.AuthorWithInheritance" json:"author"` + bookapp.Book `tstype:",extends"` + TextBook *bookapp.TextBook[T] `tstype:",extends,required"` } diff --git a/tygo/write_toplevel.go b/tygo/write_toplevel.go index 130e536..8468d34 100644 --- a/tygo/write_toplevel.go +++ b/tygo/write_toplevel.go @@ -240,7 +240,6 @@ func getInheritedType(f ast.Expr, tag *structtag.Tag) (name string, valid bool) _, isStruct := dcl.Type.(*ast.StructType) valid = isStruct && dcl.Name.IsExported() name = dcl.Name.Name - break } } case *ast.IndexExpr: @@ -248,7 +247,6 @@ func getInheritedType(f ast.Expr, tag *structtag.Tag) (name string, valid bool) if valid { generic := getIdent(ft.Index.(*ast.Ident).Name) name += fmt.Sprintf("<%s>", generic) - break } case *ast.IndexListExpr: name, valid = getInheritedType(ft.X, tag) @@ -258,7 +256,6 @@ func getInheritedType(f ast.Expr, tag *structtag.Tag) (name string, valid bool) generic += fmt.Sprintf("%s, ", getIdent(index.(*ast.Ident).Name)) } name += fmt.Sprintf("<%s>", generic[:len(generic)-2]) - break } case *ast.SelectorExpr: valid = ft.Sel.IsExported() @@ -270,7 +267,6 @@ func getInheritedType(f ast.Expr, tag *structtag.Tag) (name string, valid bool) if !tag.HasOption("required") { name = fmt.Sprintf("Partial<%s>", name) } - return name, valid } }