bel

package module
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 18, 2019 License: MIT Imports: 16 Imported by: 2

README

bel

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

Go Report Card GoDoc gocover.run

Open in Gitpod

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.

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):

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:

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):

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

Advanced Usage

You can try all the examples mentioned below in Gitpod.

FollowStructs

Follow structs enable the transitive generation of types. See examples/embed-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.

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.

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.

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.

Enums

See 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.

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

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func EmbedStructs

func EmbedStructs(e *extractor)

EmbedStructs produces a single monolithic structure where all referenced/contained subtypes become a nested Typescript struct

func FollowStructs

func FollowStructs(e *extractor)

FollowStructs enables transitive extraction of structs. By default we just emit that struct's name.

func GenerateEnumAsSumType

func GenerateEnumAsSumType(opt *generateOptions)

GenerateEnumAsSumType causes enums to be be rendered as sum types

func Render

func Render(types []TypescriptType, cfg ...GenerateOption) error

Render produces TypeScript code

func SortAlphabetically

func SortAlphabetically(e *extractor)

SortAlphabetically sorts all types and their members alphabetically

Types

type AnonStructNamer

type AnonStructNamer func(reflect.StructField) string

AnonStructNamer gives a name to an otherwise anonymous struct

type DocHandler

type DocHandler interface {
	// Type retrieves documentation for a type
	Type(t reflect.Type) string

	// Method retrieves documentation for an interface's method
	Method(parent reflect.Type, method reflect.Method) string
}

DocHandler provides documentation for types

type EnumHandler

type EnumHandler interface {
	// IsEnum determines whether a type is an enum or not
	IsEnum(t reflect.Type) bool

	// GetMember returns all members of an enum
	GetMember(t reflect.Type) ([]TypescriptEnumMember, error)
}

EnumHandler can determine if a type is an "enum" and retrieve its options

type ExtractOption

type ExtractOption func(*extractor)

ExtractOption is an option used with the Extract function

func CustomNamer

func CustomNamer(namer TypeNamer) ExtractOption

CustomNamer sets a custom function for translating Golang naming convention to Typescript naming convention. This function does not have to translate the type names, just the way they are written.

func NameAnonStructs

func NameAnonStructs(namer AnonStructNamer) ExtractOption

NameAnonStructs enables non-monolithic extraction of anonymous structs. Consider `struct { foo: struct { bar: int } }` where foo has an anonymous struct as type - with NameAnonStructs set, we'd extract that struct as its own Typescript interface.

func WithDocumentation

func WithDocumentation(handler DocHandler) ExtractOption

WithDocumentation configures a documentation handler which extracts documentation for types and methods.

func WithEnumerations

func WithEnumerations(handler EnumHandler) ExtractOption

WithEnumerations configures an enum handler which detects and extracts enums from types and constants.

type GenerateOption

type GenerateOption func(*generateOptions)

GenerateOption is an option used with the Generate function

func GenerateAdditionalPreamble

func GenerateAdditionalPreamble(preamble string) GenerateOption

GenerateAdditionalPreamble produces additional output at the beginning of the Typescript code

func GenerateNamespace

func GenerateNamespace(ns string) GenerateOption

GenerateNamespace produces a namespace in which the generated types live

func GenerateOutputTo

func GenerateOutputTo(out io.Writer) GenerateOption

GenerateOutputTo sets the writer to which we'll write the generated TS code

func GeneratePreamble

func GeneratePreamble(preamble string) GenerateOption

GeneratePreamble produces output at the beginning of the Typescript code

type ParsedSourceDocHandler

type ParsedSourceDocHandler struct {
	// contains filtered or unexported fields
}

ParsedSourceDocHandler provides Go doc documentation from

func NewParsedSourceDocHandler

func NewParsedSourceDocHandler(srcdir, base string) (*ParsedSourceDocHandler, error)

NewParsedSourceDocHandler creates a new doc handler with a single pkg in its index

func (*ParsedSourceDocHandler) AddToIndex

func (h *ParsedSourceDocHandler) AddToIndex(src, pkg string) error

AddToIndex adds another package to the handler's index. src is the path to the Go src folder of the package, pkg is its import path

func (*ParsedSourceDocHandler) Method

func (h *ParsedSourceDocHandler) Method(parent reflect.Type, method reflect.Method) string

Method retrieves documentation for a method using the handler's index

func (*ParsedSourceDocHandler) Type

Type retrieves documentation for a type using the handler's index

type ParsedSourceEnumHandler

type ParsedSourceEnumHandler struct {
	// contains filtered or unexported fields
}

ParsedSourceEnumHandler discovers enums from type and const statements

func NewParsedSourceEnumHandler

func NewParsedSourceEnumHandler(srcdir string) (*ParsedSourceEnumHandler, error)

NewParsedSourceEnumHandler creates a new enum handler that parses source code to discover enums

func (*ParsedSourceEnumHandler) GetMember

GetMember returns all members/values of an enum

func (*ParsedSourceEnumHandler) IsEnum

IsEnum returns true if the given type is an enumeration

type TypeNamer

type TypeNamer func(reflect.Type) string

TypeNamer translates Go type name convention to Typescript name convention. This function does not have to map Go types to Typescript types.

type TypedElement

type TypedElement struct {
	Name string
	Type TypescriptType
}

TypedElement pairs a name with a type

type TypescriptEnumMember

type TypescriptEnumMember struct {
	Name    string
	Value   string
	Comment string
}

TypescriptEnumMember is a member of a Typescript enum

type TypescriptKind

type TypescriptKind string

TypescriptKind is the kind of a Typescript type (akin to the kind of Go types)

const (
	// TypescriptSimpleKind means the type is merely a symbol
	TypescriptSimpleKind TypescriptKind = "simple"
	// TypescriptArrayKind means the type is an array
	TypescriptArrayKind TypescriptKind = "array"
	// TypescriptMapKind means the type is a map/dict
	TypescriptMapKind TypescriptKind = "map"
	// TypescriptInterfaceKind means the type is an interface
	TypescriptInterfaceKind TypescriptKind = "iface"
	// TypescriptEnumKind means the type is an enum
	TypescriptEnumKind TypescriptKind = "enum"
)

type TypescriptMember

type TypescriptMember struct {
	TypedElement
	Comment    string
	IsOptional bool
	IsFunction bool
	Args       []TypedElement
}

TypescriptMember is a member of a Typescript interface

type TypescriptType

type TypescriptType struct {
	Name        string
	Comment     string
	Kind        TypescriptKind
	Members     []TypescriptMember
	Params      []TypescriptType
	EnumMembers []TypescriptEnumMember
}

TypescriptType describes a type in the Typescript world

func Extract

func Extract(s interface{}, opts ...ExtractOption) ([]TypescriptType, error)

Extract uses reflection to extract the information required to generate Typescript code

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL