Git Product home page Git Product logo

martok's Introduction

Martok - Glory To Your Schema!

Build Status codecov

image

Martok is built for one thing and one thing only: converting Typescript schemas into kotlinx.serialization schemas. It's the brutal and chaotic rival to Dukat.

Why Kotlin? Why Typescript?

We've always been big believers in Kotlin Multiplatform for Mobile -- but also recognize the (well-earned) dominance of Node on the backend. Martok creates an automated schema pipeline from the Typescript in your backend codebase to the Kotlin data layer in your Android & iOS apps.

Why Not QuickType?

QuickType has gotten quite old and difficult to develop. The PRs have mostly stagnated, we currently cannot find a way to successfully build the project, so we've moved on.

Can I see some example output?

Sure! Check out the comparison files we use for our automated tests HERE.

For a quick example:

export type Unions = {
  foo: { bar: string } | { baz: string };
};

Would translate to

@Serializable
data class Unions(
    val foo: Foo
) {
    @Serializable
    data class Foo(
        val bar: String? = null,
        val baz: String? = null
    )
}

Installation

npm install -g martok

Usage

# Martok works with single files, directories, and always infers the right thing to do.
martok ./someFile.d.ts -o Schema.kt --package example
martok ./someDirectory -o BigSchema.kt
martok ./someDirectory -o ./outputDirectory # produce lots of little files.

SUPPORTS

  • Multiple source files
  • Output to multiple files or a single mega-file
  • Interfaces + Inheritance
  • Type Aliases + Intersections + Unions
  • string, number, boolean, Arrays, any
  • Anonymous types
  • Cross-references to other types
  • kotlinx.serializable
  • kotlinx.datetime (When annotated with @Date or @DateTime. See HERE for examples)
  • Custom package name
  • Enums
  • optional fields
  • Typescript "Utility" types (e.g. Omit and Pick)
  • Configurable numeric precision via the @precision jsdoc tag

TODO

  • Zod (this is so hard - PRs accepted!)
  • Fully discriminated/disagreeing unions
  • documentation
  • Intended for .d.ts files. Work on safer execution for .ts

martok's People

Contributors

asarazan avatar sam-bunger avatar vaudevillen avatar dependabot[bot] avatar

Stargazers

Phil Oliver avatar Bojan Belic avatar Tudor Luca avatar Sebas LG avatar Csaba Huszar avatar  avatar Sasikanth avatar Alice T'Poteat avatar Micko Cabacungan avatar Sebastian Schuberth avatar Dana Dzik avatar

Watchers

 avatar  avatar

martok's Issues

Tagged unions can generate confusing "duplicate" classes.

The tagged union generator creates a great sealed class cluster, but if the types it's referencing are declared/named elsewhere in the codebase, it does not delete those types from the output, causing some very confusing and similarly named classes, which are ripe for user error. You can see the failing tests in the https://github.com/asarazan/martok/tree/fix/vestigial_code branch.

Some possible approaches:

Delete the node from input as soon as we know it'll be in a tagged union

This is tricky because A) It's order-dependent and our compiler is single-pass, and B) it doesn't guarantee that other sections of the code aren't doing weird things with that reference in their own right. We could try walking all references and swapping them for the tagged version, but that might not be provably correct in all cases.

Delete the kotlin class from the output

It might actually be simpler to let the compiler do its magic and then erase/postprocess the undesired classes out of existence before returning. It shares some drawbacks with above, and has an added complication of "not all paths return klasses, some return strings (we kludged out on things like typedef).

Just do the multiple-pass upgrade already

Please no ๐Ÿ˜ญ

Just let folks know that if they don't want extraneous output, they should declare the unioned types anonymously

I fully admit that this kinda sucks, and becomes an overly prescriptive constraint on how backend organizes their code. I don't like it much either.

it'd be nice to have generated enums instead of string literals when disambiguating union types

When union types share a property of type string that's used to disambiguate them, it'd be nice if enums were automatically created.

Here, a union type is used to generate a sealed class, and the property actionType is used to disambiguate them:

The generated file looks like this:

It'd be great if there was a nested enum class called ActionType. That way we could create simple switch statements to go through the different possible types. And also when checking for the actionType, we wouldn't need to compare strings which would be brittle and prone to refactoring errors.

generated kotlin sealed classes from typescript unions allow multiple types for a property when only one is valid

If a sealed class is generated from type unions, sometimes the property can only have one valid type (like a specific case in an enum), but that's not reflected in the generated class.

For example, this typescript file for type SketchyUpdate will generate the kotlin sealed class SketchyUpdate with an inner type SketchyUpdateLifecycleEvent:

SketchyUpdateLifecycleEvent.actionType can only be ActionType.LIFECYCLE_EVENT, but that's not reflected in the generated class, and it is possible to initialize the class with the wrong ActionType.

Interfaces don't play nice with `@expand`

I think it comes down to either a bug or a misapplication of typescript's compiler API: typeToString, which will reduce and rasterize all complex type data into a simple runtime type.

Unfortunately it only does this reliably for export type Foo and not export interface Foo ๐Ÿ˜ญ

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.