Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/csweichel/bel

Generate TypeScript interfaces from Go structs/interfaces - useful for JSON RPC
https://github.com/csweichel/bel

Last synced: 2 days ago
JSON representation

Generate TypeScript interfaces from Go structs/interfaces - useful for JSON RPC

Awesome Lists containing this project

README

        

# [bel](https://en.wikipedia.org/wiki/Bel_(mythology))
Generate TypeScript interfaces from Go structs/interfaces - useful for JSON RPC

[![Go Report Card](https://goreportcard.com/badge/github.com/32leaves/bel)](https://goreportcard.com/report/github.com/32leaves/bel)
[![GoDoc](https://godoc.org/github.com/32leaves/bel?status.svg)](https://godoc.org/github.com/32leaves/bel)
[![gocover.run](https://gocover.run/github.com/32leaves/bel.svg?style=flat&tag=1.10)](https://gocover.run?tag=1.10&repo=github.com%2F32leaves%2Fbel)
[![Stability: Active](https://masterminds.github.io/stability/active.svg)](https://masterminds.github.io/stability/active.html)

[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io#github.com/32leaves/bel)

`bel` is used in production in https://gitpod.io.

## Getting started
`bel` is easy to use. There are two steps involved: extract the Typescript information, and generate the Typescript code.
```Go
package main

import (
"github.com/32leaves/bel"
)

type Demo struct {
Foo string `json:"foo,omitempty"`
Bar uint32
Baz struct {
FirstField bool
SecondField *string
}
}

func main() {
ts, err := bel.Extract(Demo{})
if err != nil {
panic(err)
}

err = bel.Render(ts)
if err != nil {
panic(err)
}
}
```

produces something akin to (sans formatting):

```TypeScript
export interface Demo {
foo?: string
Bar: number
Baz: {
FirstField: boolean
SecondField: string
}
}
```

### Converting interfaces
You can also convert Golang interfaces to TypeScript interfaces. This is particularly handy for JSON RPC:
```Go
package main

import (
"os"
"github.com/32leaves/bel"
)

type DemoService interface {
SayHello(name, msg string) (string, error)
}

func main() {
ts, err := bel.Extract((*DemoService)(nil))
if err != nil {
panic(err)
}

err = bel.Render(ts)
if err != nil {
panic(err)
}
}
```

produces something akin to (sans formatting):

```TypeScript
export interface DemoService {
SayHello(arg0: string, arg1: string): string
}
```

## Advanced Usage
You can try all the examples mentioned below in [Gitpod](https://gitpod.io#github.com/32leaves/bel).

### FollowStructs
Follow structs enable the transitive generation of types. See [examples/embed-structs.go](examples/follow-structs.go).

would produce code for the interface `UserService`, as well as the struct it refers to `AddUserRequest`, and `User` because it's referenced by `AddUserRequest`.
Without `FollowStructs` we'd simply refer to the types by name, but would not generate code for them.

### SortAlphabetically
SortAlphabetically sorts all types and their members by alphabetical order.
This produces more deterministic/stable output, which is great for making things comparable across pull requests.
See [examples/sort-alphabetically.go](examples/sort-alphabetically.go).

### EmbedStructs
Embed structs is similar to `FollowStructs` except that it produces a single canonical type for each structure.
Whenever one struct references another, that reference is resolved and the definition of the other is embedded.
See [examples/embed-structs.go](examples/embed-structs.go).

### NameAnonStructs
`NameAnonStructs` is kind of the opposite of `EmbedStructs`. When we encounter a nested anonymous struct, we make give this previously anonymous structure a name and refer to it using this name.
See [examples/name-anon-structs.go](examples/name-anon-structs.go).

### CustomNamer
`CustomNamer` enables full control over the TypeScript type names. This is handy to enforce a custom coding guideline, or to add a prefix/suffix to the generated type names.
See [examples/custom-namer.go](examples/custom-namer.go).

### Enums
See [examples/enums.go](examples/enums.go).

Go famously does not have enums, but rather type aliases and consts. Using reflection alone there is no way to obtain a comprehensive list of type values, as the linker might optimize and remove some.
_bel_ supports the extraction of enums by parsing the Go source code. Note that this is merely a heuristic and may fail in your case. If it does not work, _bel_ falls back to the underlying type.

Enums can be generated as TypeScript `enum` or as sum types. Use the `bel.GenerateEnumsAsSumTypes` flag to change this behaviour.

### Code Generation
See [examples/code-generation.go](examples/code-generation.go).

When generating the TypeScript code you might want to wrap everything in a namespace. To that end `bel.GenerateNamespace("myNamespaceName")` can be used.

By default _bel_ adds a comment to the files it generates. You can influcence this comment (and any other code that comes before the generated code)
using `bel.GeneratePreamble` and `bel.GenerateAdditionalPreamble`.

You can configure the `io.Writer` that _bel_ uses using `bel.GenerateOutputTo`.

# Contributing
All contributions/PR/issue/beer are welcome ❤️.

It's easiest to work with _bel_ using Gitpod: [![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io#github.com/32leaves/bel)