Skip to content

Commit f20ea57

Browse files
authored
Continuous improvements: Tuples, TypeUnions, descriptor extraction (#21)
* change tuple constructor to use an iterator, so it's not indexed based (and so a little less fragile) * distinct the given serializers, before generating * make a distinction between a type alias (to one type) and type union (helps with the 'brand typing' option') - change the formatting of type unions - * add kotest * fix extracting SerialDescriptors from within subclasses * additional test for serializer extraction from sealed classes * document polymorphic descriptor extraction
1 parent 38d9f64 commit f20ea57

File tree

15 files changed

+196
-52
lines changed

15 files changed

+196
-52
lines changed

buildSrc/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ object Versions {
1717
const val kotlinxSerialization = "1.3.2"
1818
const val ksp = "1.6.10-1.0.4"
1919

20-
const val kotest = "5.1.0"
20+
const val kotest = "5.2.3"
2121
}
2222

2323

docs/code/example/example-tuple-01.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,14 @@ data class SimpleTypes(
2727
element(SimpleTypes::privateMember)
2828
}
2929
) {
30-
override fun tupleConstructor(elements: List<*>): SimpleTypes {
30+
override fun tupleConstructor(elements: Iterator<*>): SimpleTypes {
3131
// When deserializing, the elements will be available as a list, in the order defined
3232
return SimpleTypes(
33-
elements[0] as String,
34-
elements[1] as Int,
35-
elements[2] as Double,
36-
elements[3] as Boolean,
37-
elements[4] as String,
33+
elements.next() as String,
34+
elements.next() as Int,
35+
elements.next() as Double,
36+
elements.next() as Boolean,
37+
elements.next() as String,
3838
)
3939
}
4040
}

docs/code/example/example-tuple-02.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ data class OptionalFields(
2222
element(OptionalFields::nullableOptionalString)
2323
}
2424
) {
25-
override fun tupleConstructor(elements: List<*>): OptionalFields {
25+
override fun tupleConstructor(elements: Iterator<*>): OptionalFields {
2626
val iter = elements.iterator()
2727
return OptionalFields(
2828
iter.next() as String,

docs/code/example/example-tuple-03.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ data class Coordinates(
2020
element(Coordinates::z)
2121
}
2222
) {
23-
override fun tupleConstructor(elements: List<*>): Coordinates {
23+
override fun tupleConstructor(elements: Iterator<*>): Coordinates {
2424
return Coordinates(
25-
elements[0] as Int,
26-
elements[1] as Int,
27-
elements[2] as Int,
25+
elements.next() as Int,
26+
elements.next() as Int,
27+
elements.next() as Int,
2828
)
2929
}
3030
}

docs/code/test/PolymorphismTest.kt

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,9 @@ class PolymorphismTest {
7575
.shouldBe(
7676
// language=TypeScript
7777
"""
78-
|export type Project = Project.DeprecatedProject | Project.OProj;
78+
|export type Project =
79+
| | Project.DeprecatedProject
80+
| | Project.OProj;
7981
|
8082
|export namespace Project {
8183
| export enum Type {
@@ -108,7 +110,10 @@ class PolymorphismTest {
108110
.shouldBe(
109111
// language=TypeScript
110112
"""
111-
|export type Dog = Dog.Golden | Dog.Mutt | Dog.NovaScotia;
113+
|export type Dog =
114+
| | Dog.Golden
115+
| | Dog.Mutt
116+
| | Dog.NovaScotia;
112117
|
113118
|export namespace Dog {
114119
| export enum Type {
@@ -185,7 +190,9 @@ class PolymorphismTest {
185190
.shouldBe(
186191
// language=TypeScript
187192
"""
188-
|export type Response = Response.EmptyResponse | Response.TextResponse;
193+
|export type Response =
194+
| | Response.EmptyResponse
195+
| | Response.TextResponse;
189196
|
190197
|export namespace Response {
191198
| export enum Type {

docs/polymorphism.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,9 @@ fun main() {
163163
> You can get the full code [here](./code/example/example-polymorphic-sealed-class-01.kt).
164164
165165
```typescript
166-
export type Project = Project.DeprecatedProject | Project.OProj;
166+
export type Project =
167+
| Project.DeprecatedProject
168+
| Project.OProj;
167169

168170
export namespace Project {
169171
export enum Type {
@@ -231,7 +233,10 @@ fun main() {
231233
> You can get the full code [here](./code/example/example-polymorphic-sealed-class-02.kt).
232234
233235
```typescript
234-
export type Dog = Dog.Golden | Dog.Mutt | Dog.NovaScotia;
236+
export type Dog =
237+
| Dog.Golden
238+
| Dog.Mutt
239+
| Dog.NovaScotia;
235240

236241
export namespace Dog {
237242
export enum Type {
@@ -322,7 +327,9 @@ fun main() {
322327
> You can get the full code [here](./code/example/example-polymorphic-objects-01.kt).
323328
324329
```typescript
325-
export type Response = Response.EmptyResponse | Response.TextResponse;
330+
export type Response =
331+
| Response.EmptyResponse
332+
| Response.TextResponse;
326333

327334
export namespace Response {
328335
export enum Type {

docs/tuples.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,14 @@ data class SimpleTypes(
5858
element(SimpleTypes::privateMember)
5959
}
6060
) {
61-
override fun tupleConstructor(elements: List<*>): SimpleTypes {
61+
override fun tupleConstructor(elements: Iterator<*>): SimpleTypes {
6262
// When deserializing, the elements will be available as a list, in the order defined
6363
return SimpleTypes(
64-
elements[0] as String,
65-
elements[1] as Int,
66-
elements[2] as Double,
67-
elements[3] as Boolean,
68-
elements[4] as String,
64+
elements.next() as String,
65+
elements.next() as Int,
66+
elements.next() as Double,
67+
elements.next() as Boolean,
68+
elements.next() as String,
6969
)
7070
}
7171
}
@@ -111,7 +111,7 @@ data class OptionalFields(
111111
element(OptionalFields::nullableOptionalString)
112112
}
113113
) {
114-
override fun tupleConstructor(elements: List<*>): OptionalFields {
114+
override fun tupleConstructor(elements: Iterator<*>): OptionalFields {
115115
val iter = elements.iterator()
116116
return OptionalFields(
117117
iter.next() as String,
@@ -154,11 +154,11 @@ data class Coordinates(
154154
element(Coordinates::z)
155155
}
156156
) {
157-
override fun tupleConstructor(elements: List<*>): Coordinates {
157+
override fun tupleConstructor(elements: Iterator<*>): Coordinates {
158158
return Coordinates(
159-
elements[0] as Int,
160-
elements[1] as Int,
161-
elements[2] as Int,
159+
elements.next() as Int,
160+
elements.next() as Int,
161+
elements.next() as Int,
162162
)
163163
}
164164
}

modules/kxs-ts-gen-core/build.gradle.kts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,11 @@ plugins {
66
buildsrc.convention.`maven-publish`
77
kotlin("plugin.serialization")
88
// id("org.jetbrains.reflekt")
9+
id("io.kotest.multiplatform")
910
}
1011

1112
val kotlinxSerializationVersion = "1.3.2"
13+
val kotestVersion = "5.2.2"
1214

1315
kotlin {
1416

@@ -70,6 +72,12 @@ kotlin {
7072
val commonTest by getting {
7173
dependencies {
7274
implementation(kotlin("test"))
75+
76+
implementation("io.kotest:kotest-assertions-core:$kotestVersion")
77+
implementation("io.kotest:kotest-assertions-json:$kotestVersion")
78+
implementation("io.kotest:kotest-property:$kotestVersion")
79+
implementation("io.kotest:kotest-framework-engine:$kotestVersion")
80+
implementation("io.kotest:kotest-framework-datatest:$kotestVersion")
7381
}
7482
}
7583
// val nativeMain by getting
@@ -81,6 +89,11 @@ kotlin {
8189
implementation(kotlin("reflect"))
8290
}
8391
}
84-
// val jvmTest by getting
92+
93+
val jvmTest by getting {
94+
dependencies {
95+
implementation("io.kotest:kotest-runner-junit5-jvm:$kotestVersion")
96+
}
97+
}
8598
}
8699
}

modules/kxs-ts-gen-core/src/commonMain/kotlin/dev/adamko/kxstsgen/KxsTsGenerator.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ open class KxsTsGenerator(
6868

6969
open fun generate(vararg serializers: KSerializer<*>): String {
7070
return serializers
71+
.toSet()
7172

7273
// 1. get all SerialDescriptors from a KSerializer
7374
.flatMap { serializer ->

modules/kxs-ts-gen-core/src/commonMain/kotlin/dev/adamko/kxstsgen/core/KxsTsSourceCodeGenerator.kt

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,17 @@ abstract class KxsTsSourceCodeGenerator(
1717
is TsDeclaration.TsEnum -> generateEnum(element)
1818
is TsDeclaration.TsInterface -> generateInterface(element)
1919
is TsDeclaration.TsNamespace -> generateNamespace(element)
20-
is TsDeclaration.TsTypeAlias -> generateType(element)
20+
is TsDeclaration.TsTypeUnion -> generateTypeUnion(element)
21+
is TsDeclaration.TsTypeAlias -> generateTypeAlias(element)
2122
is TsDeclaration.TsTuple -> generateTuple(element)
2223
}
2324
}
2425

2526
abstract fun generateEnum(enum: TsDeclaration.TsEnum): String
2627
abstract fun generateInterface(element: TsDeclaration.TsInterface): String
2728
abstract fun generateNamespace(namespace: TsDeclaration.TsNamespace): String
28-
abstract fun generateType(element: TsDeclaration.TsTypeAlias): String
29+
abstract fun generateTypeAlias(element: TsDeclaration.TsTypeAlias): String
30+
abstract fun generateTypeUnion(element: TsDeclaration.TsTypeUnion): String
2931
abstract fun generateTuple(tuple: TsDeclaration.TsTuple): String
3032

3133
abstract fun generateMapTypeReference(tsMap: TsLiteral.TsMap): String
@@ -117,17 +119,13 @@ abstract class KxsTsSourceCodeGenerator(
117119
}
118120

119121

120-
override fun generateType(element: TsDeclaration.TsTypeAlias): String {
121-
val aliases =
122-
element.typeRefs
123-
.map { generateTypeReference(it) }
124-
.sorted()
125-
.joinToString(" | ")
122+
override fun generateTypeAlias(element: TsDeclaration.TsTypeAlias): String {
123+
val aliasedRef = generateTypeReference(element.typeRef)
126124

127125
return when (config.typeAliasTyping) {
128126
KxsTsConfig.TypeAliasTypingConfig.None ->
129127
"""
130-
|export type ${element.id.name} = ${aliases};
128+
|export type ${element.id.name} = ${aliasedRef};
131129
""".trimMargin()
132130
KxsTsConfig.TypeAliasTypingConfig.BrandTyping -> {
133131

@@ -141,12 +139,31 @@ abstract class KxsTsSourceCodeGenerator(
141139
}.joinToString("")
142140

143141
"""
144-
|export type ${element.id.name} = $aliases & { __${brandType}__: void };
142+
|export type ${element.id.name} = $aliasedRef & { __${brandType}__: void };
145143
""".trimMargin()
146144
}
147145
}
148146
}
149147

148+
override fun generateTypeUnion(element: TsDeclaration.TsTypeUnion): String {
149+
return if (element.typeRefs.isEmpty()) {
150+
"""
151+
|export type ${element.id.name} = ${generatePrimitive(TsLiteral.Primitive.TsUnknown)};
152+
""".trimMargin()
153+
} else {
154+
val aliases = element.typeRefs
155+
.map { "${config.indent}| ${generateTypeReference(it)}" }
156+
.sorted()
157+
.joinToString("\n")
158+
159+
"""
160+
¦export type ${element.id.name} =
161+
¦$aliases;
162+
""".trimMargin("¦")
163+
}
164+
}
165+
166+
150167
override fun generateTuple(tuple: TsDeclaration.TsTuple): String {
151168

152169
val types = tuple.elements.joinToString(separator = ", ") {

0 commit comments

Comments
 (0)