diff --git a/src/compiler/lib/build.gradle.kts b/src/compiler/lib/build.gradle.kts index 3d820345..bc3dd659 100644 --- a/src/compiler/lib/build.gradle.kts +++ b/src/compiler/lib/build.gradle.kts @@ -3,6 +3,7 @@ import Versions.KOTLIN_COMPILER plugins { kotlin("multiplatform") kotlin("jvm") apply false + id("com.goncalossilva.resources") version "0.4.0" } group = "${Settings.GROUP_ID}.compiler" @@ -45,6 +46,11 @@ kotlin { } val jsMain by getting { dependsOn(commonMain) + dependencies{ + implementation(kotlin("test-annotations-common")) + implementation(kotlin("test-junit")) + implementation("com.goncalossilva:resources:0.4.0") + } } } } diff --git a/src/compiler/lib/src/jsMain/kotlin/community/flock/wirespec/compiler/lib/Ast.kt b/src/compiler/lib/src/jsMain/kotlin/community/flock/wirespec/compiler/lib/Ast.kt index ccd2c2b0..5c5aefff 100644 --- a/src/compiler/lib/src/jsMain/kotlin/community/flock/wirespec/compiler/lib/Ast.kt +++ b/src/compiler/lib/src/jsMain/kotlin/community/flock/wirespec/compiler/lib/Ast.kt @@ -2,6 +2,7 @@ package community.flock.wirespec.compiler.lib +import community.flock.wirespec.compiler.core.parse.Comment import community.flock.wirespec.compiler.core.parse.Endpoint import community.flock.wirespec.compiler.core.parse.Enum import community.flock.wirespec.compiler.core.parse.Field @@ -22,8 +23,8 @@ fun WsNode.consume(): Node = fun WsEndpoint.consume(): Endpoint = Endpoint( - comment = null, - identifier = Identifier(name), + comment = comment?.let { Comment(it) }, + identifier = Identifier(identifier), method = method.consume(), path = path.map { it.consume() }, query = query.map { it.consume() }, @@ -52,6 +53,30 @@ private fun WsMethod.consume() = when (this) { private fun WsIdentifier.consume() = Identifier(value) +private fun WsEnum.consume() = Enum( + identifier = Identifier(identifier), + comment = comment?.let { Comment(it) }, + entries = entries.toSet() +) + +private fun WsRefined.consume() = Refined( + identifier = Identifier(identifier), + comment = comment?.let { Comment(it) }, + validator = Refined.Validator(validator) +) + +private fun WsType.consume() = Type( + identifier = Identifier(identifier), + comment = comment?.let { Comment(it) }, + shape = Type.Shape(shape.value.map { it.consume() }) +) + +private fun WsUnion.consume() = Union( + identifier = Identifier(identifier), + comment = comment?.let { Comment(it) }, + entries = entries.map { it.consume() }.toSet() +) + private fun WsField.consume() = Field( identifier = identifier.consume(), reference = reference.consume(), @@ -113,9 +138,13 @@ private fun WsPrimitiveType.consume() = fun Node.produce(): WsNode = when (this) { - is Type -> WsType(identifier.value, shape.produce()) + is Type -> WsType( + identifier = identifier.value, + comment = comment?.value, + shape = shape.produce()) is Endpoint -> WsEndpoint( - name = identifier.value, + identifier = identifier.value, + comment = comment?.value, method = method.produce(), path = path.produce(), query = query.produce(), @@ -125,9 +154,20 @@ fun Node.produce(): WsNode = responses = responses.produce(), ) - is Enum -> WsEnum(identifier.value, entries.toTypedArray()) - is Refined -> WsRefined(identifier.value, validator.value) - is Union -> WsUnion(identifier.value, entries + is Enum -> WsEnum( + identifier = identifier.value, + comment = comment?.value, + entries = entries.toTypedArray() + ) + is Refined -> WsRefined( + identifier = identifier.value, + comment = comment?.value, + validator = validator.value + ) + is Union -> WsUnion( + identifier = identifier.value, + comment = comment?.value, + entries = entries .map { it.produce() } .toTypedArray()) } @@ -193,18 +233,23 @@ private fun List.produce() = map { it.produce() }.toTypedArra @JsExport sealed interface WsNode { - val name: String + val identifier: String } @JsExport -data class WsType(override val name: String, val shape: WsShape) : WsNode +data class WsType( + override val identifier: String, + val comment: String?, + val shape: WsShape +) : WsNode @JsExport data class WsShape(val value: Array) @JsExport data class WsEndpoint( - override val name: String, + override val identifier: String, + val comment: String?, val method: WsMethod, val path: Array, val query: Array, @@ -215,13 +260,25 @@ data class WsEndpoint( ) : WsNode @JsExport -data class WsEnum(override val name: String, val entries: Array) : WsNode +data class WsEnum( + override val identifier: String, + val comment: String?, + val entries: Array +) : WsNode @JsExport -data class WsUnion(override val name: String, val entries: Array) : WsNode +data class WsUnion( + override val identifier: String, + val comment: String?, + val entries: Array +) : WsNode @JsExport -data class WsRefined(override val name: String, val validator: String) : WsNode +data class WsRefined( + override val identifier: String, + val comment: String?, + val validator: String +) : WsNode @JsExport enum class WsMethod { GET, POST, PUT, DELETE, OPTIONS, HEAD, PATCH, TRACE } diff --git a/src/compiler/lib/src/jsTest/kotlin/community/flock/wirespec/compiler/lib/TestLib.kt b/src/compiler/lib/src/jsTest/kotlin/community/flock/wirespec/compiler/lib/TestLib.kt new file mode 100644 index 00000000..d1fb772a --- /dev/null +++ b/src/compiler/lib/src/jsTest/kotlin/community/flock/wirespec/compiler/lib/TestLib.kt @@ -0,0 +1,29 @@ +package community.flock.wirespec.compiler.lib + +import arrow.core.Either +import arrow.core.NonEmptyList +import com.goncalossilva.resources.Resource +import community.flock.wirespec.compiler.core.WirespecSpec +import community.flock.wirespec.compiler.core.compile +import community.flock.wirespec.compiler.core.emit.common.Emitted +import community.flock.wirespec.compiler.core.emit.common.Emitter +import community.flock.wirespec.compiler.core.exceptions.WirespecException +import community.flock.wirespec.compiler.core.parse +import community.flock.wirespec.compiler.utils.noLogger +import kotlin.test.Test +import kotlin.test.assertEquals + +class TestLib { + + @Test + fun testProduceConsume(){ + val source = Resource("src/jsTest/resources/person.ws").readText() + println(source) + val res = WirespecSpec.parse(source)(noLogger) + res.map { ast -> + val output = ast.produce() + val input = output.map { it.consume() } + assertEquals(input, ast) + } + } +} \ No newline at end of file diff --git a/src/compiler/lib/src/jsTest/resources/person.ws b/src/compiler/lib/src/jsTest/resources/person.ws new file mode 100644 index 00000000..2f1ddea3 --- /dev/null +++ b/src/compiler/lib/src/jsTest/resources/person.ws @@ -0,0 +1,47 @@ +type TodoIdentifier /^[0-9a-f]{8}\b-[0-9a-f]{4}\b-[0-9a-f]{4}\b-[0-9a-f]{4}\b-[0-9a-f]{12}$/g +type Name /^[0-9a-zA-Z]{1,50}$/g +type DutchPostalCode /^([0-9]{4}[A-Z]{2})$/g +type Date /^([0-9]{2}-[0-9]{2}-20[0-9]{2})$/g + +type Address { + street: Name, + houseNumber: Integer, + postalCode: DutchPostalCode +} + +type Person { + firstname: Name, + lastName: Name, + age: Integer, + address: Address +} + +type Todo { + id: TodoIdentifier, + person: Person, + done: Boolean, + prio: Integer, + date: Date +} + +type Error { + reason: String +} + +endpoint GetTodos GET /todos -> { + 200 -> Todo[] +} + +endpoint PostTodo POST Todo /todos -> { + 200 -> Todo +} + +endpoint PutTodo PUT Todo /todos/{id: TodoIdentifier} -> { + 200 -> Todo + 404 -> Error +} + +endpoint DeleteTodo DELETE /todos/{id: TodoIdentifier} -> { + 200 -> Todo + 404 -> Error +}