MaximeRVY / io-ts-codegen

Code generation for io-ts

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Motivation

Generate both static and runtime types from an intermediate language.

The intermediate language can in turn be generated from other schemas: JSON Schema, Swagger, metarpheus, etc..

Usage

Nodes of the intermediate language can be built from the provided builders.

import * as gen from 'io-ts-codegen'

// list of type declarations
const declarations = [
  gen.typeDeclaration('Persons', gen.arrayCombinator(gen.identifier('Person'))),
  gen.typeDeclaration(
    'Person',
    gen.interfaceCombinator([gen.property('name', gen.stringType), gen.property('age', gen.numberType)])
  )
]

// apply topological sort in order to get the right order
const sorted = gen.sort(declarations)

console.log(sorted.map(d => gen.printRuntime(d)).join('\n'))
console.log(sorted.map(d => gen.printStatic(d)).join('\n'))

Output (as string)

const Person = t.interface({
  name: t.string,
  age: t.number
})
const Persons = t.array(Person)
interface Person {
  name: string
  age: number
}
type Persons = Array<Person>

The aliasPattern helper

import * as gen from 'io-ts-codegen'

const declaration = gen.aliasPattern(
  'Person',
  gen.interfaceCombinator([gen.property('name', gen.stringType), gen.property('age', gen.numberType)])
)

console.log(gen.printStatic(declaration) + '\n')
console.log(gen.printRuntime(declaration) + '\n')

Output (as string)

interface Person {
  name: string,
  age: number
}
interface PersonOutput extends t.OutputOf<typeof _Person> {}
interface PersonProps extends t.PropsOf<typeof _Person> {}

const _Person = t.interface({
  name: t.string,
  age: t.number
})
const Person = t.alias(_Person)<Person, PersonOutput, PersonProps>()

Example: converting JSON Schema

import * as t from 'io-ts-codegen'

export interface StringSchema {
  type: 'string'
}

export interface NumberSchema {
  type: 'number'
}

export interface BooleanSchema {
  type: 'boolean'
}

export interface ObjectSchema {
  type: 'object'
  properties: { [key: string]: JSONSchema }
  required?: Array<string>
}

export type JSONSchema = StringSchema | NumberSchema | BooleanSchema | ObjectSchema

function getRequiredProperties(schema: ObjectSchema): { [key: string]: true } {
  const required: { [key: string]: true } = {}
  if (schema.required) {
    schema.required.forEach(function(k) {
      required[k] = true
    })
  }
  return required
}

function toInterfaceCombinator(schema: ObjectSchema): t.InterfaceCombinator {
  const required = getRequiredProperties(schema)
  return t.interfaceCombinator(
    Object.keys(schema.properties).map(key =>
      t.property(key, to(schema.properties[key]), !required.hasOwnProperty(key))
    )
  )
}

export function to(schema: JSONSchema): t.TypeReference {
  switch (schema.type) {
    case 'string':
      return t.stringType
    case 'number':
      return t.numberType
    case 'boolean':
      return t.booleanType
    case 'object':
      return toInterfaceCombinator(schema)
  }
}

const schema: JSONSchema = {
  type: 'object',
  properties: {
    foo: {
      type: 'string'
    }
  },
  required: ['foo']
}

t.printStatic(to(schema))
/*
Output:

{
  foo: string
}
*/

t.printRuntime(to(schema))
/*
Output:

t.interface({
  foo: t.string
})
*/

About

Code generation for io-ts

License:MIT License


Languages

Language:TypeScript 100.0%