Skip to content

Commit

Permalink
Merge pull request #17 from v-yarotsky/vy-yaml
Browse files Browse the repository at this point in the history
Add YAML support
  • Loading branch information
gzuidhof committed Mar 6, 2023
2 parents 584a7fe + eeca9e7 commit 5ca20f4
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 1 deletion.
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,36 @@ export interface ABCD<
}
```

## YAML support

Tygo supports generating typings for YAML-serializable objects that can be understood by Go apps.
By default, Tygo will respect `yaml` Go struct tags, in addition to `json`, but it will not apply any transformations to untagged fields.
However, the default behavior of the popular `gopkg.in/yaml.v2` package for Go structs without tags is to downcase the struct field names.
To emulate this behavior, one can use the `flavor` configuration option:

```yaml
packages:
- path: "github.com/my/package"
output_path: "webapp/api/types.ts"
flavor: "yaml"
```

```go
// Golang input
type Foo struct {
TaggedField string `yaml:"custom_field_name_in_yaml"`
UntaggedField string
}
```

```typescript
// Typescript output
export interface Foo {
custom_field_name_in_yaml: string;
untaggedfield: string;
}
```

## Related projects

- [**typescriptify-golang-structs**](https://github.com/tkrajina/typescriptify-golang-structs): Probably the most popular choice. The downside of this package is that it relies on reflection rather than parsing, which means that certain things can't be kept such as comments without adding a bunch of tags to your structs. The CLI generates a Go file which is then executed and reflected on, and its library requires you to manually specify all types that should be converted.
Expand Down
14 changes: 14 additions & 0 deletions examples/yaml/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Code generated by tygo. DO NOT EDIT.

//////////
// source: yaml.go

export interface YAMLTest {
id: string;
prefs: { [key: string]: {
foo: number /* uint32 */;
}};
address?: string;
nickname?: string;
thiswillgetlowercased: string;
}
16 changes: 16 additions & 0 deletions examples/yaml/yaml.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package yaml

type YAMLTest struct {
ID string `yaml:"id"`

Preferences map[string]struct {
Foo uint32 `yaml:"foo"`
} `yaml:"prefs"`

MaybeFieldWithStar *string `yaml:"address"`
Nickname string `yaml:"nickname,omitempty"`

ThisWillGetLowercased string

unexported bool // Unexported fields won't be in the output
}
3 changes: 3 additions & 0 deletions tygo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,6 @@ packages:
# Generate the "time" output example, note the output is in gitignore as it's pretty big
- path: "time"
output_path: "./examples/time/index.ts"
- path: "github.com/gzuidhof/tygo/examples/yaml"
output_path: "./examples/yaml/index.ts"
flavor: "yaml"
24 changes: 24 additions & 0 deletions tygo/config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package tygo

import (
"fmt"
"log"
"path/filepath"
"strings"
Expand Down Expand Up @@ -35,6 +36,12 @@ type PackageConfig struct {

// FallbackType defines the Typescript type used as a fallback for unknown Go types.
FallbackType string `yaml:"fallback_type"`

// Flavor defines what the key names of the output types will look like.
// Supported values: "default", "" (same as "default"), "yaml".
// In "default" mode, `json` and `yaml` tags are respected, but otherwise keys are unchanged.
// In "yaml" mode, keys are lowercased to emulate gopkg.in/yaml.v2.
Flavor string `yaml:"flavor"`
}

type Config struct {
Expand All @@ -56,13 +63,30 @@ func (c Config) PackageConfig(packagePath string) *PackageConfig {
if pc.Indent == "" {
pc.Indent = " "
}

var err error
pc.Flavor, err = normalizeFlavor(pc.Flavor)
if err != nil {
log.Fatalf("Invalid config for package %s: %s", packagePath, err)
}
return pc
}
}
log.Fatalf("Config not found for package %s", packagePath)
return nil
}

func normalizeFlavor(flavor string) (string, error) {
switch flavor {
case "", "default":
return "default", nil
case "yaml":
return "yaml", nil
default:
return "", fmt.Errorf("Unsupported flavor: %s", flavor)
}
}

func (c PackageConfig) IsFileIgnored(pathToFile string) bool {
basename := filepath.Base(pathToFile)
for _, ef := range c.ExcludeFiles {
Expand Down
16 changes: 15 additions & 1 deletion tygo/write.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,16 @@ func (g *PackageGenerator) writeStructFields(s *strings.Builder, fields []*ast.F

optional = jsonTag.HasOption("omitempty")
}
yamlTag, err := tags.Get("yaml")
if err == nil {
name = yamlTag.Name
if name == "-" {
continue
}

optional = yamlTag.HasOption("omitempty")
}

tstypeTag, err := tags.Get("tstype")
if err == nil {
tstype = tstypeTag.Name
Expand All @@ -212,7 +222,11 @@ func (g *PackageGenerator) writeStructFields(s *strings.Builder, fields []*ast.F
}

if len(name) == 0 {
name = fieldName
if g.conf.Flavor == "yaml" {
name = strings.ToLower(fieldName)
} else {
name = fieldName
}
}

g.writeCommentGroupIfNotNil(s, f.Doc, depth+1)
Expand Down

0 comments on commit 5ca20f4

Please sign in to comment.