From 73c2f9de6d92d748d745a57b48a0e46e0dc78204 Mon Sep 17 00:00:00 2001 From: Willem Veelenturf Date: Tue, 21 Nov 2023 12:56:58 +0100 Subject: [PATCH] Add javascript types for AST (#129) --- src/compiler/lib/build.gradle.kts | 2 + src/compiler/lib/src/jsMain/kotlin/Ast.kt | 196 +++++++++++++++++- .../lib/src/jsMain/kotlin/Compiler.kt | 17 +- 3 files changed, 213 insertions(+), 2 deletions(-) diff --git a/src/compiler/lib/build.gradle.kts b/src/compiler/lib/build.gradle.kts index 5c5622d1..e7eec9b5 100644 --- a/src/compiler/lib/build.gradle.kts +++ b/src/compiler/lib/build.gradle.kts @@ -14,6 +14,7 @@ repositories { kotlin { js { nodejs() + generateTypeScriptDefinitions() binaries.library() compilations["main"].packageJson { customField("name", "@flock/wirespec") @@ -34,6 +35,7 @@ kotlin { dependencies { implementation(project(":src:compiler:cli")) implementation(project(":src:compiler:core")) + implementation(project(":src:openapi")) } } val jsMain by getting { diff --git a/src/compiler/lib/src/jsMain/kotlin/Ast.kt b/src/compiler/lib/src/jsMain/kotlin/Ast.kt index 7ca5e38a..b0bc00c1 100644 --- a/src/compiler/lib/src/jsMain/kotlin/Ast.kt +++ b/src/compiler/lib/src/jsMain/kotlin/Ast.kt @@ -1,3 +1,197 @@ +import community.flock.wirespec.compiler.core.parse.nodes.Endpoint +import community.flock.wirespec.compiler.core.parse.nodes.Enum +import community.flock.wirespec.compiler.core.parse.nodes.Node +import community.flock.wirespec.compiler.core.parse.nodes.Refined +import community.flock.wirespec.compiler.core.parse.nodes.Type + +@ExperimentalJsExport +internal fun List.produce(): Array = map { + when (it) { + is Type -> WsType(it.name, it.shape.produce()) + is Endpoint -> WsEndpoint( + name = it.name, + method = it.method.produce(), + path= it.path.produce(), + query= it.query.produce(), + headers= it.headers.produce(), + cookies= it.cookies.produce(), + requests= it.requests.produce(), + responses= it.responses.produce(), + + ) + is Enum -> WsEnum(it.name, it.entries.toTypedArray()) + is Refined -> WsRefined(it.name, it.validator.value) + } +}.toTypedArray() + +private fun Type.Shape.produce() = WsShape( + value.map { it.produce() }.toTypedArray() +) + +@ExperimentalJsExport +private fun List.produce(): Array = map{when(it){ + is Endpoint.Segment.Literal -> WsLiteral(it.value) + is Endpoint.Segment.Param -> WsParam(it.identifier.produce(), it.reference.produce()) +}}.toTypedArray() + +@ExperimentalJsExport +private fun Type.Shape.Field.produce() = WsField(identifier.produce(), reference.produce(), isNullable) + +@ExperimentalJsExport +private fun List.produce() = map{it.produce()}.toTypedArray() + +@ExperimentalJsExport +private fun Type.Shape.Field.Identifier.produce() = WsIdentifier(this.value) + +@ExperimentalJsExport +private fun Type.Shape.Field.Reference.produce() = when(this){ + is Type.Shape.Field.Reference.Any -> WsAny(isIterable, isMap) + is Type.Shape.Field.Reference.Custom -> WsCustom(value, isIterable, isMap) + is Type.Shape.Field.Reference.Primitive -> WsPrimitive(type.produce(), isIterable, isMap) +} + +@ExperimentalJsExport +private fun Type.Shape.Field.Reference.Primitive.Type.produce() = when(this){ + Type.Shape.Field.Reference.Primitive.Type.String -> WsPrimitiveType.String + Type.Shape.Field.Reference.Primitive.Type.Integer -> WsPrimitiveType.Integer + Type.Shape.Field.Reference.Primitive.Type.Number -> WsPrimitiveType.Number + Type.Shape.Field.Reference.Primitive.Type.Boolean -> WsPrimitiveType.Boolean +} + +@ExperimentalJsExport +private fun Endpoint.Method.produce() = when (this){ + Endpoint.Method.GET -> WsMethod.GET + Endpoint.Method.POST -> WsMethod.POST + Endpoint.Method.PUT -> WsMethod.PUT + Endpoint.Method.DELETE -> WsMethod.DELETE + Endpoint.Method.OPTIONS -> WsMethod.OPTIONS + Endpoint.Method.HEAD -> WsMethod.HEAD + Endpoint.Method.PATCH -> WsMethod.PATCH + Endpoint.Method.TRACE -> WsMethod.TRACE +} + +@ExperimentalJsExport +private fun Endpoint.Content.produce() = WsContent(type, reference.produce(), isNullable) + +@ExperimentalJsExport +private fun Endpoint.Request.produce() = WsRequest(content?.produce()) + +@ExperimentalJsExport +private fun List.produce() = map{it.produce()}.toTypedArray() + + +@ExperimentalJsExport +private fun Endpoint.Response.produce() = WsResponse(status, content?.produce()) + +@ExperimentalJsExport +private fun List.produce() = map{it.produce()}.toTypedArray() +@JsExport +@ExperimentalJsExport +sealed interface WsNode + +@JsExport +@ExperimentalJsExport +data class WsType(val name: String, val shape: WsShape) : WsNode + +@JsExport +@ExperimentalJsExport +data class WsShape(val value: Array) + + +@JsExport +@ExperimentalJsExport +data class WsEndpoint( + val name: String, + val method: WsMethod, + val path: Array, + val query: Array, + val headers: Array, + val cookies: Array, + val requests: Array, + val responses: Array +) : WsNode + +@JsExport +@ExperimentalJsExport +data class WsEnum(val name: String, val entries: Array) : WsNode + +@JsExport +@ExperimentalJsExport +data class WsRefined(val name: String, val validator: String) : WsNode + +@JsExport +@ExperimentalJsExport +enum class WsMethod { GET, POST, PUT, DELETE, OPTIONS, HEAD, PATCH, TRACE } + +@JsExport +@ExperimentalJsExport +sealed interface WsSegment + +@JsExport +@ExperimentalJsExport +data class WsLiteral(val value: String) : WsSegment +@JsExport +@ExperimentalJsExport +data class WsParam( + val identifier: WsIdentifier, + val reference: WsReference +) : WsSegment + + +@JsExport +@ExperimentalJsExport +data class Shape(val value: Array) + +@JsExport +@ExperimentalJsExport +data class WsField(val identifier: WsIdentifier, val reference: WsReference, val isNullable: Boolean) { + +} + +@JsExport +@ExperimentalJsExport +data class WsIdentifier(val value: String) + +@JsExport +@ExperimentalJsExport +sealed interface WsReference { + val isIterable: Boolean + val isMap: Boolean + + +} + +@JsExport +@ExperimentalJsExport +data class WsAny(override val isIterable: Boolean, override val isMap: Boolean = false) : WsReference +@JsExport +@ExperimentalJsExport +data class WsCustom( + val value: String, + override val isIterable: Boolean, + override val isMap: Boolean = false +) : WsReference + +@JsExport +@ExperimentalJsExport +data class WsPrimitive( + val type: WsPrimitiveType, + override val isIterable: Boolean, + override val isMap: Boolean = false +) : WsReference + +@JsExport +@ExperimentalJsExport +enum class WsPrimitiveType { String, Integer, Number, Boolean } + +@JsExport +@ExperimentalJsExport +data class WsRequest(val content: WsContent?) + +@JsExport +@ExperimentalJsExport +data class WsResponse(val status: String, val content: WsContent?) + @JsExport @ExperimentalJsExport -class Ast(val value: Array) +data class WsContent(val type: String, val reference: WsReference, val isNullable: Boolean = false) diff --git a/src/compiler/lib/src/jsMain/kotlin/Compiler.kt b/src/compiler/lib/src/jsMain/kotlin/Compiler.kt index 6b9d3474..94895d43 100644 --- a/src/compiler/lib/src/jsMain/kotlin/Compiler.kt +++ b/src/compiler/lib/src/jsMain/kotlin/Compiler.kt @@ -6,6 +6,8 @@ import community.flock.wirespec.compiler.core.emit.WirespecEmitter import community.flock.wirespec.compiler.core.parse.Parser import community.flock.wirespec.compiler.core.tokenize.tokenize import community.flock.wirespec.compiler.utils.Logger +import community.flock.wirespec.openapi.v2.OpenApiParser as OpenApiParserV2 +import community.flock.wirespec.openapi.v3.OpenApiParser as OpenApiParserV3 @JsExport @ExperimentalJsExport @@ -17,7 +19,6 @@ abstract class Compiler { fun parse(source: String) = Wirespec.tokenize(source) .let { Parser(logger).parse(it) } - .let { Ast(arrayOf()) } companion object { protected val logger = object : Logger() {} @@ -53,3 +54,17 @@ class WsToWirespec : Compiler() { private val wirespecEmitter = WirespecEmitter(logger) } } + +@JsExport +@ExperimentalJsExport +class OpenApiV2 { + fun parse(source: String):Array = OpenApiParserV2.parse(source).produce() + +} + +@JsExport +@ExperimentalJsExport +class OpenApiV3 { + fun parse(source: String):Array = OpenApiParserV3.parse(source).produce() + +}