Ecosyste.ms: Awesome

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

Awesome Lists | Featured Topics | Projects

https://github.com/bwireman/genus

Type Script and Elixir structs, a monster mash
https://github.com/bwireman/genus

Last synced: 6 days ago
JSON representation

Type Script and Elixir structs, a monster mash

Awesome Lists containing this project

README

        

# Genus

Macro for generating Typescript types and Elixir structs

## Installation

```elixir
def deps do
[
{:genus, git: "[email protected]:bwireman/genus.git"}
]
end
```

## Usage

```elixir
defmodule User do
# load the `tschema` macro
use Genus
tschema name: "User" do
field(:id, :string, required: true)
field(:email, :string)
field(:active, :bool, default: false)
field(:role, :union, "Role", true, [:enduser, :admin, :superuser], default: :enduser)
end
end
```

### Macro Options

- name: Name of the generated TypeScript interface, defaults to the last piece of the module name
- imports: keyword of other imports and import overrides to add to the generated file

### Elixir output

```elixir
defmodule User do
@enforce_keys [:id]
defstruct [id: nil, email: nil, active: false, role: :enduser]
end
```

### Typescript output

```typescript
// Do Not Modify! This file was generated by Genus from an Elixir struct @ Elixir.User
// https://github.com/bwireman/genus

export type Role = "enduser" | "admin" | "superuser"

export interface User {
id: string
email?: string
active: boolean
role: Role
}

export const apply_user = (v: any): User => v

export const build_user = ({ id, email, active, role }: {
id: string
email?: string
active?: boolean
role?: Role
}): User => {
return {
id: id,
email: email || undefined,
active: active || false,
role: role || "enduser",
}
}

export const new_user = (id: string) => build_user({ id })
```

### Config

```elixir
import Config

config :genus,
# path directory to save the write TypeScript code to
# defaults to "./ts"
directory: "types",
# indent spacer for generated TypeScript
# defaults to " "
indent: "\t"
```

## Types

| Format | Elixir type | TS type |
| -------------------------------------------- | ----------- | ----------- |
| (name, :string) | String.t() | string |
| (name, :integer) | integer() | number |
| (name, :float) | float() | number |
| (name, :bool) | bool() | boolean |
| (name) | any() | any |
| (name, :external, type_name) | any() | type_name |
| (name, :list, type_name) | list() | type_name[] |
| (name, :union, type_name, is_string, values) | any() | type_name |

#### Type Options

- type_name `String.t()`: represents the TS type to use
- is_string `bool()`: Should the union be represented as strings in TS
- values `list()`: Values that compose the union

## Field Options

#### `default: value` | `required: true|false`

Fields default to being optional and with a `nil` default in Elixir and nullable with a default of `undefined` in TypeScript. If you specify a value that will be the default value in both Elixir and Typescript. You can also specify `required:` and mark the field as required in both the Elixir struct and the generator function