Skip to content

Refine implementation #14

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 47 commits into from
Apr 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
a651496
- #1 basic lists implementation
aSemy Mar 4, 2022
63ec8d0
map tests #2 #3
aSemy Mar 4, 2022
239c1b8
generate implementations and test improvements
aSemy Mar 4, 2022
dbdca26
suppress warning in tests
aSemy Mar 4, 2022
ec52c3f
`export enum` -> valid for .d.ts files
aSemy Mar 4, 2022
220ba8e
test for ignoring fields with @Transient, and if an interface has no …
aSemy Mar 4, 2022
301cf88
test for objects, and fix test expectations in polymophic classes, so…
aSemy Mar 4, 2022
5155ffe
try fixing knit gradle task warning
aSemy Mar 4, 2022
d23c4e1
- replace jacoco with kotlinx.kover
aSemy Mar 4, 2022
29f40b0
bump gradle version
aSemy Mar 26, 2022
995179f
set max line length to 100
aSemy Mar 26, 2022
3c47a24
mucking about with plugins and compilation processors
aSemy Mar 26, 2022
1ae7c9a
tidy up gradle config
aSemy Mar 26, 2022
4e3a6f6
refactor kxs generator
aSemy Mar 26, 2022
7924e2a
update tests, and add some more
aSemy Mar 26, 2022
71bde73
major refactor to get things more like a library, and steps towards h…
aSemy Apr 1, 2022
439c075
sealed classes working!
aSemy Apr 2, 2022
9faff4a
some Sealed interfaces and type ref improvements
aSemy Apr 2, 2022
52e0e25
temp fix for open poly classes
aSemy Apr 3, 2022
ed28d6d
normalize knit code comparisons
aSemy Apr 3, 2022
44d01c1
update tests after temp fix for open poly classes
aSemy Apr 3, 2022
053ff3e
update sealed poly tests
aSemy Apr 3, 2022
ac2cafa
rm migrated code
aSemy Apr 3, 2022
ee2f3d1
rm unneeded TsTypeRef.Unknown
aSemy Apr 3, 2022
5331cd4
rename TsType to TsTypeAlias, and update docs in tsElements.kt
aSemy Apr 3, 2022
dc1fd81
code cleanup, documentation
aSemy Apr 3, 2022
48f5d24
docs, more Maps tests/examples/workarounds
aSemy Apr 3, 2022
fa883b1
update gitattributes
aSemy Apr 3, 2022
6f3ad4e
rename 'knit' subproject to 'code'
aSemy Apr 3, 2022
aa13efa
prep for jitpack
aSemy Apr 3, 2022
e0583a3
docs update
aSemy Apr 3, 2022
ffd1a72
improve recursive descriptor extraction
aSemy Apr 3, 2022
83cacea
version bum git-versioning plugin
aSemy Apr 3, 2022
b093dac
better helper function for mutable maps with default puts
aSemy Apr 3, 2022
674b6df
simplify the API
aSemy Apr 3, 2022
cac1dcb
code tidup
aSemy Apr 3, 2022
c78b77a
formatting, code tidying
aSemy Apr 3, 2022
0889352
kmm gradle config tidy up
aSemy Apr 3, 2022
759740b
bump gradle version
aSemy Apr 3, 2022
43cfb94
add jitpack button
aSemy Apr 3, 2022
9e5cac5
fix maven publishing
aSemy Apr 3, 2022
d7f6686
update project name & group
aSemy Apr 3, 2022
bcb3c0a
disable reflekt dependency
aSemy Apr 3, 2022
bf7ae56
Merge branch 'main' into dev
aSemy Apr 4, 2022
cad7b30
#1 add more tests/docs for lists and maps
aSemy Apr 4, 2022
8db48ce
add links to README
aSemy Apr 4, 2022
3ae531f
- workaround for json content polymorphic + test
aSemy Apr 4, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 26 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@

# Kotlinx Serialization TypeScript Generator

Create TypeScript interfaces from Kotlinx Serialization classes.
[Kotlinx Serialization TypeScript Generator](https://github.com/adamko-dev/kotlinx-serialization-typescript-generator)
creates TypeScript interfaces from
[Kotlinx Serialization](https://github.com/Kotlin/kotlinx.serialization/)
classes.

```kotlin
@Serializable
Expand Down Expand Up @@ -39,23 +42,31 @@ The Kotlinx Serialization API should be used to generate TypeScript. The
[`SerialDescriptor`s](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.descriptors/-serial-descriptor/index.html)
are flexible and comprehensive enough to allow for accurate TypeScript code, without any deviation.

The aim is to create TypeScript interfaces that can accurately produce Kotlinx Serialization
compatible JSON.

The Kotlinx Serialization API should be used to generate TypeScript. The
[`SerialDescriptor`s](https://kotlin.github.io/kotlinx.serialization/kotlinx-serialization-core/kotlinx.serialization.descriptors/-serial-descriptor/index.html)
are flexible and comprehensive enough to allow for accurate TypeScript code, without any deviation.

See [the docs](./docs) for working examples.

## Status

This is a proof-of-concept.

| | Status | Notes |
|---------------------------------------|----------------------------------------------------------|:-------------------------------------------------------------------------------------------------|
| Kotlin multiplatform | ❓ | The codebase is multiplatform, but only JVM has been tested |
| `@SerialName` | ✅/⚠ | The serial name is directly converted and might produce invalid TypeScript |
| Basic classes | ✅ [example](./docs/basic-classes.md) | |
| Nullable and default-value properties | ✅ [example](./docs/default-values.md) | |
| Value classes | ✅ [example](./docs/value-classes.md) | |
| Enums | ✅ [example](./docs/enums.md) | |
| Lists | ✅ [example](./docs/lists.md) | |
| Maps | ✅/⚠ [example](./docs/maps.md) | Maps with complex keys are converted to an ES6 Map, [see](./docs/maps.md#maps-with-complex-keys) |
| Polymorphism - Sealed classes | ✅/⚠ [example](./docs/polymorphism.md#sealed-classes) | Nested sealed classes are ignored, [see](./docs/polymorphism.md#nested-sealed-classes) |
| Polymorphism - Open classes | ❌ [example](./docs/abstract-classes.md) | Not implemented. Converted to `type MyClass = any` |
| `@JsonClassDiscriminator` | ❌ | Not implemented |
| Edge cases - circular dependencies | ✅ [example](./docs/edgecases.md) | |
| | Status | Notes |
|---------------------------------------|-----------------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------|
| Kotlin multiplatform | ❓ | The codebase is multiplatform, but only JVM has been tested |
| `@SerialName` | ✅/⚠ | The serial name is directly converted and might produce invalid TypeScript |
| Basic classes | ✅ [example](./docs/basic-classes.md) | |
| Nullable and default-value properties | ✅ [example](./docs/default-values.md) | |
| Value classes | ✅ [example](./docs/value-classes.md) | |
| Enums | ✅ [example](./docs/enums.md) | |
| Lists | ✅ [example](./docs/lists.md) | |
| Maps | ✅/⚠ [example](./docs/maps.md) | Maps with complex keys are converted to an ES6 Map, [see documentation](./docs/maps.md#maps-with-complex-keys) |
| Polymorphism - Sealed classes | ✅/⚠ [example](./docs/polymorphism.md#sealed-classes) | Nested sealed classes are ignored, [see documentation](./docs/polymorphism.md#nested-sealed-classes) |
| Polymorphism - Open classes | ❌ [example](./docs/abstract-classes.md) | Not implemented. Converted to `type MyClass = any` |
| `@JsonClassDiscriminator` | ❌ | Not implemented |
| JSON Content polymorphism | ❌ [example](./docs/polymorphism.md#json-content-polymorphism) | Not implemented. Converted to `type MyClass = any` |
| Edge cases - circular dependencies | ✅ [example](./docs/edgecases.md) | |
2 changes: 1 addition & 1 deletion docs/code/example/example-generics-01.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import dev.adamko.kxstsgen.*
import kotlinx.serialization.builtins.serializer

@Serializable
class Box<T>(
class Box<T : Number>(
val value: T,
)

Expand Down
31 changes: 31 additions & 0 deletions docs/code/example/example-json-polymorphic-01.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// This file was automatically generated from polymorphism.md by Knit tool. Do not edit.
@file:Suppress("PackageDirectoryMismatch", "unused")
package dev.adamko.kxstsgen.example.exampleJsonPolymorphic01

import kotlinx.serialization.*
import dev.adamko.kxstsgen.*

import kotlinx.serialization.json.*

@Serializable
abstract class Project {
abstract val name: String
}

@Serializable
data class BasicProject(override val name: String) : Project()

@Serializable
data class OwnedProject(override val name: String, val owner: String) : Project()

object ProjectSerializer : JsonContentPolymorphicSerializer<Project>(Project::class) {
override fun selectDeserializer(element: JsonElement) = when {
"owner" in element.jsonObject -> OwnedProject.serializer()
else -> BasicProject.serializer()
}
}

fun main() {
val tsGenerator = KxsTsGenerator()
println(tsGenerator.generate(ProjectSerializer))
}
23 changes: 23 additions & 0 deletions docs/code/example/example-list-objects-01.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// This file was automatically generated from lists.md by Knit tool. Do not edit.
@file:Suppress("PackageDirectoryMismatch", "unused")
package dev.adamko.kxstsgen.example.exampleListObjects01

import kotlinx.serialization.*
import dev.adamko.kxstsgen.*

@Serializable
data class Colour(
val rgb: String
)

@Serializable
data class MyLists(
val colours: List<Colour>,
val colourGroups: Set<List<Colour>>,
val colourGroupGroups: LinkedHashSet<List<List<Colour>>>,
)

fun main() {
val tsGenerator = KxsTsGenerator()
println(tsGenerator.generate(MyLists.serializer()))
}
22 changes: 22 additions & 0 deletions docs/code/example/example-list-objects-02.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// This file was automatically generated from lists.md by Knit tool. Do not edit.
@file:Suppress("PackageDirectoryMismatch", "unused")
package dev.adamko.kxstsgen.example.exampleListObjects02

import kotlinx.serialization.*
import dev.adamko.kxstsgen.*

@Serializable
data class Colour(
val rgb: String
)

@Serializable
data class MyLists(
val listOfMaps: List<Map<String, Int>>,
val listOfColourMaps: List<Map<String, Colour>>,
)

fun main() {
val tsGenerator = KxsTsGenerator()
println(tsGenerator.generate(MyLists.serializer()))
}
4 changes: 2 additions & 2 deletions docs/code/example/example-list-primitive-01.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import dev.adamko.kxstsgen.*
@Serializable
data class MyLists(
val strings: List<String>,
val ints: List<Int>,
val longs: List<Long>,
val ints: Set<Int>,
val longs: Collection<Long>,
)

fun main() {
Expand Down
23 changes: 23 additions & 0 deletions docs/code/example/example-list-primitive-02.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// This file was automatically generated from lists.md by Knit tool. Do not edit.
@file:Suppress("PackageDirectoryMismatch", "unused")
package dev.adamko.kxstsgen.example.exampleListPrimitive02

import kotlinx.serialization.*
import dev.adamko.kxstsgen.*

@Serializable
data class Colour(
val rgb: String
)

@Serializable
data class MyLists(
val colours: List<Colour>,
val colourGroups: List<List<Colour>>,
val colourGroupGroups: List<List<List<Colour>>>,
)

fun main() {
val tsGenerator = KxsTsGenerator()
println(tsGenerator.generate(MyLists.serializer()))
}
6 changes: 3 additions & 3 deletions docs/code/example/example-map-primitive-03.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import kotlinx.serialization.*
import dev.adamko.kxstsgen.*

@Serializable
data class Config(
val properties: Map<String?, String?>
class MapsWithLists(
val mapOfLists: Map<String, List<String>>
)

fun main() {
val tsGenerator = KxsTsGenerator()
println(tsGenerator.generate(Config.serializer()))
println(tsGenerator.generate(MapsWithLists.serializer()))
}
20 changes: 20 additions & 0 deletions docs/code/example/example-map-primitive-04.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// This file was automatically generated from maps.md by Knit tool. Do not edit.
@file:Suppress("PackageDirectoryMismatch", "unused")
package dev.adamko.kxstsgen.example.exampleMapPrimitive04

import kotlinx.serialization.*
import dev.adamko.kxstsgen.*

@Serializable
@JvmInline
value class Data(val content: String)

@Serializable
class MyDataClass(
val mapOfLists: Map<String, Data>
)

fun main() {
val tsGenerator = KxsTsGenerator()
println(tsGenerator.generate(MyDataClass.serializer()))
}
16 changes: 16 additions & 0 deletions docs/code/example/example-map-primitive-05.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// This file was automatically generated from maps.md by Knit tool. Do not edit.
@file:Suppress("PackageDirectoryMismatch", "unused")
package dev.adamko.kxstsgen.example.exampleMapPrimitive05

import kotlinx.serialization.*
import dev.adamko.kxstsgen.*

@Serializable
data class Config(
val properties: Map<String?, String?>
)

fun main() {
val tsGenerator = KxsTsGenerator()
println(tsGenerator.generate(Config.serializer()))
}
43 changes: 43 additions & 0 deletions docs/code/test/ListsTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,47 @@ class ListsTests {
.normalize()
)
}

@Test
fun testExampleListObjects01() {
captureOutput("ExampleListObjects01") {
dev.adamko.kxstsgen.example.exampleListObjects01.main()
}.normalizeJoin()
.shouldBe(
// language=TypeScript
"""
|export interface MyLists {
| colours: Colour[];
| colourGroups: Colour[][];
| colourGroupGroups: Colour[][][];
|}
|
|export interface Colour {
| rgb: string;
|}
""".trimMargin()
.normalize()
)
}

@Test
fun testExampleListObjects02() {
captureOutput("ExampleListObjects02") {
dev.adamko.kxstsgen.example.exampleListObjects02.main()
}.normalizeJoin()
.shouldBe(
// language=TypeScript
"""
|export interface MyLists {
| listOfMaps: { [key: string]: number }[];
| listOfColourMaps: { [key: string]: Colour }[];
|}
|
|export interface Colour {
| rgb: string;
|}
""".trimMargin()
.normalize()
)
}
}
34 changes: 34 additions & 0 deletions docs/code/test/MapsTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,40 @@ class MapsTests {
fun testExampleMapPrimitive03() {
captureOutput("ExampleMapPrimitive03") {
dev.adamko.kxstsgen.example.exampleMapPrimitive03.main()
}.normalizeJoin()
.shouldBe(
// language=TypeScript
"""
|export interface MapsWithLists {
| mapOfLists: { [key: string]: string[] };
|}
""".trimMargin()
.normalize()
)
}

@Test
fun testExampleMapPrimitive04() {
captureOutput("ExampleMapPrimitive04") {
dev.adamko.kxstsgen.example.exampleMapPrimitive04.main()
}.normalizeJoin()
.shouldBe(
// language=TypeScript
"""
|export interface MyDataClass {
| mapOfLists: { [key: string]: Data };
|}
|
|export type Data = string;
""".trimMargin()
.normalize()
)
}

@Test
fun testExampleMapPrimitive05() {
captureOutput("ExampleMapPrimitive05") {
dev.adamko.kxstsgen.example.exampleMapPrimitive05.main()
}.normalizeJoin()
.shouldBe(
// language=TypeScript
Expand Down
30 changes: 30 additions & 0 deletions docs/code/test/PolymorphismTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -206,4 +206,34 @@ class PolymorphismTest {
.normalize()
)
}

@Test
fun testExampleGenerics01() {
captureOutput("ExampleGenerics01") {
dev.adamko.kxstsgen.example.exampleGenerics01.main()
}.normalizeJoin()
.shouldBe(
// language=TypeScript
"""
|export interface Box {
| value: number;
|}
""".trimMargin()
.normalize()
)
}

@Test
fun testExampleJsonPolymorphic01() {
captureOutput("ExampleJsonPolymorphic01") {
dev.adamko.kxstsgen.example.exampleJsonPolymorphic01.main()
}.normalizeJoin()
.shouldBe(
// language=TypeScript
"""
|export type Project = any;
""".trimMargin()
.normalize()
)
}
}
Loading