Skip to content

Commit

Permalink
Merge pull request #34 from 0x-buidl/fix/struct_ptr_inheritance
Browse files Browse the repository at this point in the history
fix: include struct pointer inheritance
  • Loading branch information
gzuidhof committed Aug 18, 2023
2 parents 6cb2668 + 3416e9c commit 57dbd87
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 21 deletions.
28 changes: 25 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,11 @@ 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<MyType>`. To mark these structs as required, use the tag `tstype:",extends,required"`.

Named `struct fields` can also be extended.

Example usage [here](examples/inheritance)

Expand All @@ -259,19 +263,37 @@ 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"`
}
```

```typescript
// Typescript output
export interface Base {
name: string;
}

export interface Base2<T extends string | number /* int */> {
id: T;
}

export interface OptionalPtr {
field: string;
}

export interface Other<T extends number /* int */>
extends Base,
Base2<T>,
Partial<OptionalPtr>,
external.AnotherStruct {
other_value: string;
}
Expand Down Expand Up @@ -330,7 +352,7 @@ packages:
// Golang input
type Foo struct {
TaggedField string `yaml:"custom_field_name_in_yaml"`
UntaggedField string
UntaggedField string
}
```

Expand Down
2 changes: 1 addition & 1 deletion examples/inheritance/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export interface Base3<T extends string, X extends number /* int */> {
class: T;
level: X;
}
export interface Other<T extends number /* int */, X extends string> extends Base, Base2<T>, Base3<X, T>, bookapp.Book, bookapp.TextBook<T> {
export interface Other<T extends number /* int */, X extends string> extends Base, Base2<T>, Partial<Base3<X, T>>, bookapp.Book, bookapp.TextBook<T> {
otherWithBase: Base;
otherWithBase2: Base2<X>;
otherValue: string;
Expand Down
22 changes: 12 additions & 10 deletions examples/inheritance/inheritance.go
Original file line number Diff line number Diff line change
@@ -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"`
Expand All @@ -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<T>" 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<T>" json:"author"`
bookapp.Book `tstype:",extends"`
TextBook *bookapp.TextBook[T] `tstype:",extends,required"`
}
19 changes: 12 additions & 7 deletions tygo/write_toplevel.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down Expand Up @@ -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 {
Expand All @@ -240,29 +240,34 @@ func getInheritedType(f ast.Expr) (name string, valid bool) {
_, isStruct := dcl.Type.(*ast.StructType)
valid = isStruct && dcl.Name.IsExported()
name = dcl.Name.Name
break
}
}
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 {
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()
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
Expand Down

0 comments on commit 57dbd87

Please sign in to comment.