From ce689d0c2bf63af96e21bc50d2ef57bada421003 Mon Sep 17 00:00:00 2001 From: Jerre van Veluw Date: Thu, 16 Nov 2023 15:39:39 +0100 Subject: [PATCH] Feat path params (#124) --- buildSrc/src/main/java/Versions.kt | 6 ++ settings.gradle.kts | 2 + src/compiler/cli/build.gradle.kts | 11 ++- .../flock/wirespec/compiler/cli/CliTest.kt | 12 +-- .../compiler/cli/io/FullFilePathTest.kt | 11 +-- src/compiler/core/build.gradle.kts | 6 +- .../wirespec/compiler/core/LanguageSpec.kt | 22 ++--- .../compiler/core/parse/EndpointParser.kt | 87 ++++++++++++------- .../core/tokenize/types/TokenTypes.kt | 14 +-- .../flock/wirespec/compiler/utils/Logger.kt | 2 +- .../flock/wirespec/compiler/common/Assert.kt | 23 ----- .../wirespec/compiler/common/TestLogger.kt | 5 -- .../wirespec/compiler/core/CompileEnumTest.kt | 16 ++-- .../compiler/core/CompileToWirespecTest.kt | 14 ++- .../wirespec/compiler/core/CompilerTest.kt | 18 ++-- .../compiler/core/parse/ParseEndpointTest.kt | 66 ++++++++++---- .../compiler/core/parse/ParserTest.kt | 22 ++--- .../core/tokenize/TokenizeEndpointTest.kt | 50 +++++------ src/compiler/lib/build.gradle.kts | 8 ++ .../lib/src/jsMain/kotlin/Compiler.kt | 2 +- .../src/main/kotlin/Annotator.kt | 2 +- .../intellij-plugin/src/main/kotlin/Lexer.kt | 2 + .../intellij-plugin/src/main/kotlin/Types.kt | 1 + src/openapi/build.gradle.kts | 1 - .../gradle/src/main/kotlin/WirespecPlugin.kt | 2 +- src/plugin/maven/src/main/kotlin/BaseMojo.kt | 2 +- types/endpoint.ws | 2 +- 27 files changed, 223 insertions(+), 186 deletions(-) delete mode 100644 src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/common/Assert.kt delete mode 100644 src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/common/TestLogger.kt diff --git a/buildSrc/src/main/java/Versions.kt b/buildSrc/src/main/java/Versions.kt index f15213343..368d7971b 100644 --- a/buildSrc/src/main/java/Versions.kt +++ b/buildSrc/src/main/java/Versions.kt @@ -1,10 +1,14 @@ import Versions.ARROW import Versions.COROUTINES +import Versions.KOTEST +import Versions.KOTEST_ARROW object Versions { const val ARROW = "1.2.1" const val COROUTINES = "1.6.4" const val INTELLIJ = "1.15.0" + const val KOTEST = "5.7.2" + const val KOTEST_ARROW = "1.4.0" } object Libraries { @@ -12,6 +16,8 @@ object Libraries { const val KOTLIN_COROUTINES = "org.jetbrains.kotlinx:kotlinx-coroutines-core:$COROUTINES" const val KOTLIN_COROUTINES_NATIVE = "org.jetbrains.kotlinx:kotlinx-coroutines-core-native:$COROUTINES" const val KOTLIN_COROUTINES_JVM = "org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:$COROUTINES" + const val KOTEST_ASSERTIONS = "io.kotest:kotest-assertions-core:$KOTEST" + const val KOTEST_ASSERTIONS_ARROW = "io.kotest.extensions:kotest-assertions-arrow:$KOTEST_ARROW" } object Plugins { diff --git a/settings.gradle.kts b/settings.gradle.kts index d6945adca..b16a1d45f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -2,11 +2,13 @@ pluginManagement { val kotlinVersion = "1.9.10" val shadowVersion = "7.1.2" + val kotestVersion = "5.7.2" plugins { kotlin("multiplatform") version kotlinVersion kotlin("jvm") version kotlinVersion id("com.github.johnrengelman.shadow") version shadowVersion + id("io.kotest.multiplatform") version kotestVersion } repositories { diff --git a/src/compiler/cli/build.gradle.kts b/src/compiler/cli/build.gradle.kts index 7e82766c4..347c022c1 100644 --- a/src/compiler/cli/build.gradle.kts +++ b/src/compiler/cli/build.gradle.kts @@ -1,3 +1,5 @@ +import Libraries.KOTEST_ASSERTIONS +import Libraries.KOTEST_ASSERTIONS_ARROW import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTargetWithHostTests import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsTargetDsl @@ -7,6 +9,7 @@ plugins { kotlin("jvm") apply false id("com.github.johnrengelman.shadow") id("com.goncalossilva.resources") version "0.4.0" + id("io.kotest.multiplatform") } group = "${Settings.GROUP_ID}.compiler" @@ -30,6 +33,11 @@ kotlin { js(IR) { build() } jvm { withJava() + java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } + } tasks { getByName("shadowJar") { archiveBaseName.set(projectName) @@ -52,9 +60,10 @@ kotlin { } commonTest { dependencies { - implementation(kotlin("test-common")) implementation(kotlin("test-annotations-common")) implementation(kotlin("test-junit")) + implementation(KOTEST_ASSERTIONS) + implementation(KOTEST_ASSERTIONS_ARROW) } } val desktopMain by creating { diff --git a/src/compiler/cli/src/commonTest/kotlin/community/flock/wirespec/compiler/cli/CliTest.kt b/src/compiler/cli/src/commonTest/kotlin/community/flock/wirespec/compiler/cli/CliTest.kt index d3cd22a20..06ad51835 100644 --- a/src/compiler/cli/src/commonTest/kotlin/community/flock/wirespec/compiler/cli/CliTest.kt +++ b/src/compiler/cli/src/commonTest/kotlin/community/flock/wirespec/compiler/cli/CliTest.kt @@ -5,9 +5,11 @@ import community.flock.wirespec.compiler.cli.io.JavaFile import community.flock.wirespec.compiler.cli.io.KotlinFile import community.flock.wirespec.compiler.cli.io.TypeScriptFile import community.flock.wirespec.compiler.core.emit.common.DEFAULT_PACKAGE_NAME +import io.kotest.matchers.booleans.shouldBeTrue +import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldContain import kotlin.test.Ignore import kotlin.test.Test -import kotlin.test.assertEquals import kotlin.test.assertTrue class CliTest { @@ -39,7 +41,7 @@ class CliTest { ) """.trimIndent() - assertEquals(expected, file) + file shouldBe expected } @Test @@ -61,7 +63,7 @@ class CliTest { ) {}; """.trimIndent() - assertEquals(expected, file) + file shouldBe expected } @Test @@ -87,7 +89,7 @@ class CliTest { ) """.trimIndent() - assertTrue(file.contains(expected)) + file.contains(expected).shouldBeTrue() } @Test @@ -138,7 +140,7 @@ class CliTest { } """.trimIndent() - assertTrue(file.contains(expected)) + file shouldContain expected } private fun getRandomString(length: Int) = (1..length) diff --git a/src/compiler/cli/src/commonTest/kotlin/community/flock/wirespec/compiler/cli/io/FullFilePathTest.kt b/src/compiler/cli/src/commonTest/kotlin/community/flock/wirespec/compiler/cli/io/FullFilePathTest.kt index 5b0928f67..f51b3f4fa 100644 --- a/src/compiler/cli/src/commonTest/kotlin/community/flock/wirespec/compiler/cli/io/FullFilePathTest.kt +++ b/src/compiler/cli/src/commonTest/kotlin/community/flock/wirespec/compiler/cli/io/FullFilePathTest.kt @@ -1,15 +1,16 @@ package community.flock.wirespec.compiler.cli.io -import kotlin.test.Ignore +import io.kotest.matchers.shouldBe import kotlin.test.Test class FullFilePathTest { @Test fun testParse() { - val result = FullFilePath.parse("/src/test/resources/test.json") - kotlin.test.assertEquals("/src/test/resources", result.directory) - kotlin.test.assertEquals("test", result.fileName) - kotlin.test.assertEquals(Extension.Json, result.extension) + FullFilePath.parse("/src/test/resources/test.json").run { + directory shouldBe "/src/test/resources" + fileName shouldBe "test" + extension shouldBe Extension.Json + } } } diff --git a/src/compiler/core/build.gradle.kts b/src/compiler/core/build.gradle.kts index 483584742..73f520d5f 100644 --- a/src/compiler/core/build.gradle.kts +++ b/src/compiler/core/build.gradle.kts @@ -1,9 +1,12 @@ import Libraries.ARROW_CORE +import Libraries.KOTEST_ASSERTIONS +import Libraries.KOTEST_ASSERTIONS_ARROW plugins { kotlin("multiplatform") kotlin("jvm") apply false id("com.github.johnrengelman.shadow") apply false + id("io.kotest.multiplatform") } group = "${Settings.GROUP_ID}.compiler" @@ -37,9 +40,10 @@ kotlin { } commonTest { dependencies { - implementation(kotlin("test-common")) implementation(kotlin("test-annotations-common")) implementation(kotlin("test-junit")) + implementation(KOTEST_ASSERTIONS) + implementation(KOTEST_ASSERTIONS_ARROW) } } } diff --git a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/LanguageSpec.kt b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/LanguageSpec.kt index cdb366503..fd8640736 100644 --- a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/LanguageSpec.kt +++ b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/LanguageSpec.kt @@ -7,21 +7,15 @@ import community.flock.wirespec.compiler.core.tokenize.types.Comma import community.flock.wirespec.compiler.core.tokenize.types.CustomRegex import community.flock.wirespec.compiler.core.tokenize.types.CustomType import community.flock.wirespec.compiler.core.tokenize.types.CustomValue -import community.flock.wirespec.compiler.core.tokenize.types.DELETE -import community.flock.wirespec.compiler.core.tokenize.types.GET -import community.flock.wirespec.compiler.core.tokenize.types.HEAD +import community.flock.wirespec.compiler.core.tokenize.types.ForwardSlash import community.flock.wirespec.compiler.core.tokenize.types.Invalid import community.flock.wirespec.compiler.core.tokenize.types.LeftCurly +import community.flock.wirespec.compiler.core.tokenize.types.Method import community.flock.wirespec.compiler.core.tokenize.types.NewLine -import community.flock.wirespec.compiler.core.tokenize.types.OPTIONS -import community.flock.wirespec.compiler.core.tokenize.types.PATCH -import community.flock.wirespec.compiler.core.tokenize.types.POST -import community.flock.wirespec.compiler.core.tokenize.types.PUT import community.flock.wirespec.compiler.core.tokenize.types.Path import community.flock.wirespec.compiler.core.tokenize.types.QuestionMark import community.flock.wirespec.compiler.core.tokenize.types.RightCurly import community.flock.wirespec.compiler.core.tokenize.types.StatusCode -import community.flock.wirespec.compiler.core.tokenize.types.TRACE import community.flock.wirespec.compiler.core.tokenize.types.TokenType import community.flock.wirespec.compiler.core.tokenize.types.WhiteSpaceExceptNewLine import community.flock.wirespec.compiler.core.tokenize.types.WsBoolean @@ -55,19 +49,13 @@ object Wirespec : LanguageSpec { Regex("^Integer") to WsInteger, Regex("^Boolean") to WsBoolean, Regex("^->") to Arrow, - Regex("^GET") to GET, - Regex("^POST") to POST, - Regex("^PUT") to PUT, - Regex("^DELETE") to DELETE, - Regex("^OPTIONS") to OPTIONS, - Regex("^HEAD") to HEAD, - Regex("^PATCH") to PATCH, - Regex("^TRACE") to TRACE, + Regex("^GET|POST|PUT|DELETE|OPTIONS|HEAD|PATCH|TRACE") to Method, Regex("^/.*/g") to CustomRegex, Regex("^[1-5][0-9][0-9]") to StatusCode, Regex("^[a-z][a-zA-Z]*") to CustomValue, Regex("^[A-Z][a-zA-Z]*") to CustomType, - Regex("^/[a-z]*") to Path, + Regex("^/[a-z]+") to Path, + Regex("^/") to ForwardSlash, Regex("^.") to Invalid // Catch all regular expression if none of the above matched ) } diff --git a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/parse/EndpointParser.kt b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/parse/EndpointParser.kt index 1ce70521e..5fd8a8dd3 100644 --- a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/parse/EndpointParser.kt +++ b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/parse/EndpointParser.kt @@ -1,29 +1,24 @@ package community.flock.wirespec.compiler.core.parse import arrow.core.Either -import arrow.core.nel import arrow.core.raise.either import community.flock.wirespec.compiler.core.exceptions.WirespecException import community.flock.wirespec.compiler.core.exceptions.WirespecException.CompilerException.ParserException.WrongTokenException import community.flock.wirespec.compiler.core.parse.nodes.Endpoint +import community.flock.wirespec.compiler.core.parse.nodes.Type import community.flock.wirespec.compiler.core.parse.nodes.Type.Shape.Field.Reference.Custom import community.flock.wirespec.compiler.core.parse.nodes.Type.Shape.Field.Reference.Primitive import community.flock.wirespec.compiler.core.tokenize.types.Arrow import community.flock.wirespec.compiler.core.tokenize.types.Brackets +import community.flock.wirespec.compiler.core.tokenize.types.Colon import community.flock.wirespec.compiler.core.tokenize.types.CustomType -import community.flock.wirespec.compiler.core.tokenize.types.DELETE -import community.flock.wirespec.compiler.core.tokenize.types.GET -import community.flock.wirespec.compiler.core.tokenize.types.HEAD +import community.flock.wirespec.compiler.core.tokenize.types.CustomValue +import community.flock.wirespec.compiler.core.tokenize.types.ForwardSlash import community.flock.wirespec.compiler.core.tokenize.types.LeftCurly import community.flock.wirespec.compiler.core.tokenize.types.Method -import community.flock.wirespec.compiler.core.tokenize.types.OPTIONS -import community.flock.wirespec.compiler.core.tokenize.types.PATCH -import community.flock.wirespec.compiler.core.tokenize.types.POST -import community.flock.wirespec.compiler.core.tokenize.types.PUT import community.flock.wirespec.compiler.core.tokenize.types.Path import community.flock.wirespec.compiler.core.tokenize.types.RightCurly import community.flock.wirespec.compiler.core.tokenize.types.StatusCode -import community.flock.wirespec.compiler.core.tokenize.types.TRACE import community.flock.wirespec.compiler.core.tokenize.types.WirespecType import community.flock.wirespec.compiler.core.tokenize.types.WsBoolean import community.flock.wirespec.compiler.core.tokenize.types.WsInteger @@ -45,8 +40,17 @@ class EndpointParser(logger: Logger) : AbstractParser(logger) { private fun TokenProvider.parseEndpointDefinition(name: String) = either { eatToken().bind() token.log() - val method = parseEndpointMethod().bind() - val path = parseEndpointPath().bind() + val method = when (token.type) { + is Method -> Endpoint.Method.valueOf(token.value) + else -> raise(WrongTokenException(token)) + }.also { eatToken().bind() } + + val segments = mutableListOf().apply { + while (token.type !is Arrow) { + add(parseEndpointSegments().bind()) + } + }.also { eatToken().bind() } + when (token.type) { is LeftCurly -> Unit else -> raise(WrongTokenException(token)) @@ -57,7 +61,7 @@ class EndpointParser(logger: Logger) : AbstractParser(logger) { Endpoint( name = name, method = method, - path = path, + path = segments, query = emptyList(), headers = emptyList(), cookies = emptyList(), @@ -66,30 +70,42 @@ class EndpointParser(logger: Logger) : AbstractParser(logger) { ) } - private fun TokenProvider.parseEndpointMethod() = either { + private fun TokenProvider.parseEndpointSegments() = either { token.log() when (token.type) { - is Method -> when (token.type as Method) { - DELETE -> Endpoint.Method.DELETE - GET -> Endpoint.Method.GET - HEAD -> Endpoint.Method.HEAD - OPTIONS -> Endpoint.Method.OPTIONS - PATCH -> Endpoint.Method.PATCH - POST -> Endpoint.Method.POST - PUT -> Endpoint.Method.PUT - TRACE -> Endpoint.Method.TRACE - } - - else -> raise(WrongTokenException(token)) - }.also { eatToken().bind() } + is Path -> Endpoint.Segment.Literal(token.value.drop(1)).also { eatToken().bind() } + is ForwardSlash -> parseEndpointSegmentParam().bind() + else -> raise(WrongTokenException(token)) + } } - private fun TokenProvider.parseEndpointPath() = either { + private fun TokenProvider.parseEndpointSegmentParam() = either { + eatToken().bind() token.log() when (token.type) { - is Path -> Endpoint.Segment.Literal(token.value.drop(1)).nel() - else -> raise(WrongTokenException(token)) - }.also { eatToken().bind() } + is LeftCurly -> eatToken().bind() + else -> raise(WrongTokenException(token)) + } + val identifier = when (token.type) { + is CustomValue -> Type.Shape.Field.Identifier(token.value).also { eatToken().bind() } + else -> raise(WrongTokenException(token)) + } + when (token.type) { + is Colon -> eatToken().bind() + else -> raise(WrongTokenException(token)) + } + val reference = when (token.type) { + is WirespecType -> parseReference(token.type as WirespecType, token.value).bind() + else -> raise(WrongTokenException(token)) + } + when (token.type) { + is RightCurly -> eatToken().bind() + else -> raise(WrongTokenException(token)) + } + Endpoint.Segment.Param( + identifier = identifier, + reference = reference + ) } private fun TokenProvider.parseEndpointResponses() = either { @@ -125,10 +141,18 @@ class EndpointParser(logger: Logger) : AbstractParser(logger) { } private fun TokenProvider.parseContent(wsType: WirespecType, value: String) = either { + token.log() + Endpoint.Content( + type = "application/json", + reference = parseReference(wsType, value).bind(), + ) + } + + private fun TokenProvider.parseReference(wsType: WirespecType, value: String) = either { eatToken().bind() token.log() val isIterable = (token.type is Brackets).also { if (it) eatToken().bind() } - val reference = when (wsType) { + when (wsType) { is WsString -> Primitive(Primitive.Type.String, isIterable) is WsInteger -> Primitive(Primitive.Type.Integer, isIterable) @@ -138,6 +162,5 @@ class EndpointParser(logger: Logger) : AbstractParser(logger) { is CustomType -> Custom(value, isIterable) } - Endpoint.Content(type = "application/json", reference = reference) } } diff --git a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/tokenize/types/TokenTypes.kt b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/tokenize/types/TokenTypes.kt index bb92ac4f9..e2c0bc5b8 100644 --- a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/tokenize/types/TokenTypes.kt +++ b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/tokenize/types/TokenTypes.kt @@ -9,6 +9,7 @@ data object RightCurly : TokenType data object Colon : TokenType data object Comma : TokenType data object QuestionMark : TokenType +data object ForwardSlash : TokenType data object Brackets : TokenType data object CustomValue : TokenType data object Invalid : TokenType @@ -35,18 +36,11 @@ data object WsNumber : WirespecType data object WsBoolean : WirespecType data object CustomType : WirespecType -sealed interface Method : Keyword -data object GET : Method -data object POST : Method -data object PUT : Method -data object DELETE : Method -data object OPTIONS : Method -data object HEAD : Method -data object PATCH : Method -data object TRACE : Method +data object Method : Keyword -data object StatusCode : Keyword data object Path : Keyword + +data object StatusCode : Keyword data object Arrow : Keyword data object CustomRegex : TokenType diff --git a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/utils/Logger.kt b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/utils/Logger.kt index 6d39601a0..55e46d137 100644 --- a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/utils/Logger.kt +++ b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/utils/Logger.kt @@ -1,6 +1,6 @@ package community.flock.wirespec.compiler.utils -open class Logger(private val enableLogging: Boolean) { +open class Logger(private val enableLogging: Boolean = false) { open fun warn(s: String) = println(s) diff --git a/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/common/Assert.kt b/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/common/Assert.kt deleted file mode 100644 index b9b9a0502..000000000 --- a/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/common/Assert.kt +++ /dev/null @@ -1,23 +0,0 @@ -package community.flock.wirespec.compiler.common - -import arrow.core.Either -import arrow.core.Nel -import community.flock.wirespec.compiler.core.exceptions.WirespecException -import kotlin.test.assertEquals -import kotlin.test.assertTrue - -inline fun Any.assert(): R = assertTrue { this is R }.let { this as R } - -fun Either, String>.assertValid(expected: String) { - when (this) { - is Either.Left -> error("Valid expected: ${this.value.first().message}", ) - is Either.Right -> assertEquals(expected, value) - } -} - -fun Either, B>.assertInvalid(expected: String) { - when (this) { - is Either.Left -> assertTrue(value.map { it.message }.contains(expected)) - is Either.Right -> error("Invalid expected") - } -} diff --git a/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/common/TestLogger.kt b/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/common/TestLogger.kt deleted file mode 100644 index f2217d6e2..000000000 --- a/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/common/TestLogger.kt +++ /dev/null @@ -1,5 +0,0 @@ -package community.flock.wirespec.compiler.common - -import community.flock.wirespec.compiler.utils.Logger - -object TestLogger : Logger(enableLogging = false) diff --git a/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/CompileEnumTest.kt b/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/CompileEnumTest.kt index 21b3df35b..15258d2e2 100644 --- a/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/CompileEnumTest.kt +++ b/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/CompileEnumTest.kt @@ -1,18 +1,18 @@ package community.flock.wirespec.compiler.core -import community.flock.wirespec.compiler.common.TestLogger -import community.flock.wirespec.compiler.common.assertValid import community.flock.wirespec.compiler.core.emit.JavaEmitter import community.flock.wirespec.compiler.core.emit.KotlinEmitter import community.flock.wirespec.compiler.core.emit.ScalaEmitter import community.flock.wirespec.compiler.core.emit.TypeScriptEmitter import community.flock.wirespec.compiler.core.emit.WirespecEmitter import community.flock.wirespec.compiler.core.emit.common.Emitter +import community.flock.wirespec.compiler.utils.noLogger +import io.kotest.assertions.arrow.core.shouldBeRight import kotlin.test.Test class CompileEnumTest { - private val logger = TestLogger + private val logger = noLogger private val compiler = compile( """ @@ -38,7 +38,7 @@ class CompileEnumTest { """.trimIndent() - compiler(KotlinEmitter(logger = logger)).assertValid(kotlin) + compiler(KotlinEmitter(logger = logger)) shouldBeRight kotlin } @Test @@ -61,7 +61,7 @@ class CompileEnumTest { """.trimIndent() - compiler(JavaEmitter(logger = logger)).assertValid(java) + compiler(JavaEmitter(logger = logger)) shouldBeRight java } @Test @@ -77,7 +77,7 @@ class CompileEnumTest { """.trimIndent() - compiler(ScalaEmitter(logger = logger)).assertValid(scala) + compiler(ScalaEmitter(logger = logger)) shouldBeRight scala } @Test @@ -87,7 +87,7 @@ class CompileEnumTest { """.trimIndent() - compiler(TypeScriptEmitter(logger = logger)).assertValid(ts) + compiler(TypeScriptEmitter(logger = logger)) shouldBeRight ts } @Test @@ -99,7 +99,7 @@ class CompileEnumTest { """.trimIndent() - compiler(WirespecEmitter(logger = logger)).assertValid(wirespec) + compiler(WirespecEmitter(logger = logger)) shouldBeRight wirespec } private fun compile(source: String) = { emitter: Emitter -> diff --git a/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/CompileToWirespecTest.kt b/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/CompileToWirespecTest.kt index 324a87830..6736c7608 100644 --- a/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/CompileToWirespecTest.kt +++ b/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/CompileToWirespecTest.kt @@ -1,13 +1,13 @@ package community.flock.wirespec.compiler.core -import community.flock.wirespec.compiler.common.TestLogger -import community.flock.wirespec.compiler.common.assertValid import community.flock.wirespec.compiler.core.emit.WirespecEmitter +import community.flock.wirespec.compiler.utils.noLogger +import io.kotest.assertions.arrow.core.shouldBeRight import kotlin.test.Test class CompileToWirespecTest { - private val logger = TestLogger + private val logger = noLogger @Test fun testCompileType() { @@ -20,9 +20,7 @@ class CompileToWirespecTest { """.trimIndent() Wirespec.compile(source)(logger)(WirespecEmitter(logger = logger)) - .map { it.first().second } - .onLeft(::println) - .assertValid(source) + .map { it.first().second } shouldBeRight source } @Test @@ -33,8 +31,6 @@ class CompileToWirespecTest { """.trimIndent() Wirespec.compile(source)(logger)(WirespecEmitter(logger = logger)) - .map { it.first().second } - .onLeft(::println) - .assertValid(source) + .map { it.first().second } shouldBeRight source } } diff --git a/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/CompilerTest.kt b/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/CompilerTest.kt index 061f97e47..5a0d62e6a 100644 --- a/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/CompilerTest.kt +++ b/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/CompilerTest.kt @@ -1,14 +1,15 @@ package community.flock.wirespec.compiler.core -import community.flock.wirespec.compiler.common.TestLogger -import community.flock.wirespec.compiler.common.assertInvalid -import community.flock.wirespec.compiler.common.assertValid import community.flock.wirespec.compiler.core.emit.KotlinEmitter +import community.flock.wirespec.compiler.utils.noLogger +import io.kotest.assertions.arrow.core.shouldBeLeft +import io.kotest.assertions.arrow.core.shouldBeRight +import io.kotest.assertions.arrow.core.shouldContain import kotlin.test.Test class CompilerTest { - private val logger = TestLogger + private val logger = noLogger @Test fun testCompileKotlin() { @@ -32,8 +33,7 @@ class CompilerTest { """.trimIndent() Wirespec.compile(source)(logger)(KotlinEmitter(logger = logger)) - .map { it.first().second } - .assertValid(out) + .map { it.first().second } shouldBeRight out } @Test @@ -48,7 +48,8 @@ class CompilerTest { """.trimIndent() Wirespec.compile(source)(logger)(KotlinEmitter(logger = logger)) - .assertInvalid("RightCurly expected, not: CustomValue at line 3 and position 3") + .shouldBeLeft() + .map { it.message } shouldContain "RightCurly expected, not: CustomValue at line 3 and position 3" } @Test @@ -68,7 +69,6 @@ class CompilerTest { Wirespec.compile(source)(logger)(KotlinEmitter(logger = logger)) .map { it.first().second } - .onLeft(::println) - .assertValid(out) + .onLeft(::println) shouldBeRight out } } diff --git a/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/parse/ParseEndpointTest.kt b/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/parse/ParseEndpointTest.kt index da0f1c62b..a3af479da 100644 --- a/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/parse/ParseEndpointTest.kt +++ b/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/parse/ParseEndpointTest.kt @@ -1,25 +1,50 @@ package community.flock.wirespec.compiler.core.parse -import community.flock.wirespec.compiler.common.TestLogger -import community.flock.wirespec.compiler.common.assert import community.flock.wirespec.compiler.core.Wirespec import community.flock.wirespec.compiler.core.parse.nodes.Endpoint import community.flock.wirespec.compiler.core.parse.nodes.Endpoint.Method.GET import community.flock.wirespec.compiler.core.parse.nodes.Endpoint.Segment.Literal +import community.flock.wirespec.compiler.core.parse.nodes.Type.Shape.Field.Identifier +import community.flock.wirespec.compiler.core.parse.nodes.Type.Shape.Field.Reference import community.flock.wirespec.compiler.core.tokenize.tokenize +import community.flock.wirespec.compiler.utils.noLogger +import io.kotest.assertions.arrow.core.shouldBeRight +import io.kotest.matchers.collections.shouldBeEmpty +import io.kotest.matchers.shouldBe +import io.kotest.matchers.types.shouldBeInstanceOf import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue -import kotlin.test.fail class ParseEndpointTest { - private fun parser() = Parser(TestLogger) + private fun parser() = Parser(noLogger) @Test - fun testParserWithCorrectInput() { + fun testEndpointParserWithCorrectInput() { val source = """ - endpoint GetTodos GET /todos { + endpoint GetTodos GET /todos -> { + 200 -> Todo[] + } + + """.trimIndent() + + Wirespec.tokenize(source) + .let(parser()::parse) + .shouldBeRight() + .also { it.size shouldBe 1 } + .first() + .shouldBeInstanceOf() + .run { + name shouldBe "GetTodos" + method shouldBe GET + path shouldBe listOf(Literal("todos")) + requests.shouldBeEmpty() + } + } + + @Test + fun testPathParamsParserWithCorrectInput() { + val source = """ + endpoint GetTodos GET /todos/{id: String} -> { 200 -> Todo } @@ -27,15 +52,24 @@ class ParseEndpointTest { Wirespec.tokenize(source) .let(parser()::parse) - .onRight { assertEquals(1, it.size) } - .onLeft { fail("Should be Right, but was Left: ${it.first()}") } - .getOrNull()!!.first() - .assert() + .shouldBeRight() + .also { it.size shouldBe 1 } + .first() + .shouldBeInstanceOf() .run { - assertEquals("GetTodos", name) - assertEquals(GET, method) - assertEquals(listOf(Literal("todos")), path) - assertTrue(requests.isEmpty()) + name shouldBe "GetTodos" + method shouldBe GET + path shouldBe listOf( + Literal("todos"), Endpoint.Segment.Param( + identifier = Identifier("id"), + reference = Reference.Primitive( + type = Reference.Primitive.Type.String, + isIterable = false, + isMap = false, + ) + ) + ) + requests.shouldBeEmpty() } } } diff --git a/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/parse/ParserTest.kt b/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/parse/ParserTest.kt index 0b5a81b35..04cfc5fb6 100644 --- a/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/parse/ParserTest.kt +++ b/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/parse/ParserTest.kt @@ -1,15 +1,16 @@ package community.flock.wirespec.compiler.core.parse -import community.flock.wirespec.compiler.common.TestLogger import community.flock.wirespec.compiler.core.Wirespec import community.flock.wirespec.compiler.core.tokenize.tokenize +import community.flock.wirespec.compiler.utils.Logger +import io.kotest.assertions.arrow.core.shouldBeLeft +import io.kotest.assertions.arrow.core.shouldBeRight +import io.kotest.matchers.shouldBe import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.fail class ParserTest { - private fun parser() = Parser(TestLogger) + private fun parser() = Parser(object : Logger(false) {}) @Test fun testParserWithCorrectInput() { @@ -23,8 +24,8 @@ class ParserTest { Wirespec.tokenize(source) .let(parser()::parse) - .onRight { assertEquals(1, it.size) } - .onLeft { fail("Should not be Either.Left") } + .shouldBeRight() + .size shouldBe 1 } @Test @@ -39,10 +40,9 @@ class ParserTest { Wirespec.tokenize(source) .let(parser()::parse) - .onLeft { - assertEquals(1, it.size) - assertEquals("RightCurly expected, not: CustomValue at line 3 and position 3", it.first().message) - } - .onRight { fail("Should not be Either.Right") } + .shouldBeLeft() + .also { it.size shouldBe 1 } + .first() + .message shouldBe "RightCurly expected, not: CustomValue at line 3 and position 3" } } diff --git a/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/tokenize/TokenizeEndpointTest.kt b/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/tokenize/TokenizeEndpointTest.kt index c819574b1..abbbc2ca8 100644 --- a/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/tokenize/TokenizeEndpointTest.kt +++ b/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/tokenize/TokenizeEndpointTest.kt @@ -3,20 +3,23 @@ package community.flock.wirespec.compiler.core.tokenize import community.flock.wirespec.compiler.core.Wirespec import community.flock.wirespec.compiler.core.tokenize.types.Arrow import community.flock.wirespec.compiler.core.tokenize.types.Brackets +import community.flock.wirespec.compiler.core.tokenize.types.Colon import community.flock.wirespec.compiler.core.tokenize.types.CustomType import community.flock.wirespec.compiler.core.tokenize.types.CustomValue import community.flock.wirespec.compiler.core.tokenize.types.EndOfProgram -import community.flock.wirespec.compiler.core.tokenize.types.GET +import community.flock.wirespec.compiler.core.tokenize.types.ForwardSlash import community.flock.wirespec.compiler.core.tokenize.types.Invalid import community.flock.wirespec.compiler.core.tokenize.types.LeftCurly +import community.flock.wirespec.compiler.core.tokenize.types.Method import community.flock.wirespec.compiler.core.tokenize.types.Path import community.flock.wirespec.compiler.core.tokenize.types.RightCurly import community.flock.wirespec.compiler.core.tokenize.types.StartOfProgram import community.flock.wirespec.compiler.core.tokenize.types.StatusCode import community.flock.wirespec.compiler.core.tokenize.types.WsEndpointDef +import community.flock.wirespec.compiler.core.tokenize.types.WsString +import io.kotest.assertions.arrow.core.shouldNotContain +import io.kotest.matchers.shouldBe import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertTrue class TokenizeEndpointTest { @@ -26,11 +29,9 @@ class TokenizeEndpointTest { val expected = listOf(StartOfProgram, EndOfProgram) - Wirespec.tokenize(source).run { - onEach { println(it.type) } - assertEquals(expected.size, size) - onEachIndexed { index, token -> assertEquals(expected[index], token.type) } - } + Wirespec.tokenize(source) + .also { it.size shouldBe expected.size } + .onEachIndexed { index, token -> token.type shouldBe expected[index] } } @Test @@ -39,11 +40,9 @@ class TokenizeEndpointTest { val expected = listOf(CustomValue, EndOfProgram) - Wirespec.tokenize(source).removeWhiteSpace().run { - onEach { println(it.type) } - assertEquals(expected.size, size) - onEachIndexed { index, token -> assertEquals(expected[index], token.type) } - } + Wirespec.tokenize(source).removeWhiteSpace() + .also { it.size shouldBe expected.size } + .onEachIndexed { index, token -> token.type shouldBe expected[index] } } @Test @@ -60,17 +59,15 @@ class TokenizeEndpointTest { EndOfProgram ) - Wirespec.tokenize(source).removeWhiteSpace().run { - onEach { println(it.type) } - assertEquals(expected.size, size) - onEachIndexed { index, token -> assertEquals(expected[index], token.type) } - } + Wirespec.tokenize(source).removeWhiteSpace() + .also { it.size shouldBe expected.size } + .onEachIndexed { index, token -> token.type shouldBe expected[index] } } @Test - fun testTokenizer() { + fun testEndpointTokenizer() { val source = """ - endpoint GetTodos GET /todos { + endpoint GetTodos GET /todos/{id: String} -> { 200 -> Todo[] 404 -> Error } @@ -78,16 +75,15 @@ class TokenizeEndpointTest { """.trimIndent() val expected = listOf( - WsEndpointDef, CustomType, GET, Path, LeftCurly, StatusCode, - Arrow, CustomType, Brackets, StatusCode, Arrow, CustomType, RightCurly, - EndOfProgram, + WsEndpointDef, CustomType, Method, Path, ForwardSlash, LeftCurly, CustomValue, Colon, WsString, + RightCurly, Arrow, LeftCurly, StatusCode, Arrow, CustomType, Brackets, StatusCode, Arrow, CustomType, + RightCurly, EndOfProgram, ) Wirespec.tokenize(source).removeWhiteSpace().run { - onEach { println(it.type) } - assertTrue(none { it.type is Invalid }) - assertEquals(expected.size, size) - onEachIndexed { index, token -> assertEquals(expected[index], token.type) } + size shouldBe expected.size + map { it.type } shouldNotContain Invalid + onEachIndexed { index, token -> token.type shouldBe expected[index] } } } } diff --git a/src/compiler/lib/build.gradle.kts b/src/compiler/lib/build.gradle.kts index 9dc309334..5c5622d1c 100644 --- a/src/compiler/lib/build.gradle.kts +++ b/src/compiler/lib/build.gradle.kts @@ -20,6 +20,14 @@ kotlin { customField("bin", mapOf("wirespec" to "wirespec-bin.js")) } } + jvm { + withJava() + java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(17)) + } + } + } sourceSets { val commonMain by getting { diff --git a/src/compiler/lib/src/jsMain/kotlin/Compiler.kt b/src/compiler/lib/src/jsMain/kotlin/Compiler.kt index 160145d86..6b9d34749 100644 --- a/src/compiler/lib/src/jsMain/kotlin/Compiler.kt +++ b/src/compiler/lib/src/jsMain/kotlin/Compiler.kt @@ -20,7 +20,7 @@ abstract class Compiler { .let { Ast(arrayOf()) } companion object { - protected val logger = object : Logger(false) {} + protected val logger = object : Logger() {} } } diff --git a/src/lsp/intellij-plugin/src/main/kotlin/Annotator.kt b/src/lsp/intellij-plugin/src/main/kotlin/Annotator.kt index 6139eac8c..7c60ebb66 100644 --- a/src/lsp/intellij-plugin/src/main/kotlin/Annotator.kt +++ b/src/lsp/intellij-plugin/src/main/kotlin/Annotator.kt @@ -15,7 +15,7 @@ import kotlinx.coroutines.runBlocking class Annotator : ExternalAnnotator, List>() { - private val logger = object : Logger(false) {} + private val logger = object : Logger() {} override fun collectInformation(file: PsiFile) = runBlocking { Wirespec.tokenize(file.text) diff --git a/src/lsp/intellij-plugin/src/main/kotlin/Lexer.kt b/src/lsp/intellij-plugin/src/main/kotlin/Lexer.kt index 95a47fa04..94cd9b1ed 100644 --- a/src/lsp/intellij-plugin/src/main/kotlin/Lexer.kt +++ b/src/lsp/intellij-plugin/src/main/kotlin/Lexer.kt @@ -11,6 +11,7 @@ import community.flock.wirespec.compiler.core.tokenize.types.CustomRegex import community.flock.wirespec.compiler.core.tokenize.types.CustomType import community.flock.wirespec.compiler.core.tokenize.types.CustomValue import community.flock.wirespec.compiler.core.tokenize.types.EndOfProgram +import community.flock.wirespec.compiler.core.tokenize.types.ForwardSlash import community.flock.wirespec.compiler.core.tokenize.types.Invalid import community.flock.wirespec.compiler.core.tokenize.types.LeftCurly import community.flock.wirespec.compiler.core.tokenize.types.Method @@ -74,6 +75,7 @@ class Lexer : IntellijLexer() { is Arrow -> Types.ARROW is Method -> Types.METHOD is Path -> Types.PATH + is ForwardSlash -> Types.FORWARD_SLASH is StatusCode -> Types.STATUS_CODE } } diff --git a/src/lsp/intellij-plugin/src/main/kotlin/Types.kt b/src/lsp/intellij-plugin/src/main/kotlin/Types.kt index 3d5d8873f..28029f73a 100644 --- a/src/lsp/intellij-plugin/src/main/kotlin/Types.kt +++ b/src/lsp/intellij-plugin/src/main/kotlin/Types.kt @@ -22,6 +22,7 @@ interface Types { val ARROW = ElementType("ARROW") val METHOD = ElementType("METHOD") val PATH = ElementType("PATH") + val FORWARD_SLASH = ElementType("FORWARD_SLASH") val STATUS_CODE = ElementType("STATUS_CODE") val LEFT_CURLY = ElementType("LEFT_CURLY") val RIGHT_CURLY = ElementType("RIGHT_CURLY") diff --git a/src/openapi/build.gradle.kts b/src/openapi/build.gradle.kts index c0505bbc0..e77b9d4ed 100644 --- a/src/openapi/build.gradle.kts +++ b/src/openapi/build.gradle.kts @@ -52,4 +52,3 @@ kotlin { } } } - diff --git a/src/plugin/gradle/src/main/kotlin/WirespecPlugin.kt b/src/plugin/gradle/src/main/kotlin/WirespecPlugin.kt index f4080483c..47f45f970 100644 --- a/src/plugin/gradle/src/main/kotlin/WirespecPlugin.kt +++ b/src/plugin/gradle/src/main/kotlin/WirespecPlugin.kt @@ -69,7 +69,7 @@ open class WirespecPluginExtension @Inject constructor(val objectFactory: Object class WirespecPlugin : Plugin { - private val logger = object : Logger(true) {} + private val logger = object : Logger() {} private fun compile(input: String, logger: Logger, emitter: Emitter) = (File(input).listFiles() ?: arrayOf()) diff --git a/src/plugin/maven/src/main/kotlin/BaseMojo.kt b/src/plugin/maven/src/main/kotlin/BaseMojo.kt index d423b1710..1be68fcde 100644 --- a/src/plugin/maven/src/main/kotlin/BaseMojo.kt +++ b/src/plugin/maven/src/main/kotlin/BaseMojo.kt @@ -11,7 +11,7 @@ import java.io.File abstract class BaseMojo : AbstractMojo() { - val logger = object : Logger(true) { + val logger = object : Logger() { override fun warn(s: String) = log.warn(s) override fun log(s: String) = log.info(s) } diff --git a/types/endpoint.ws b/types/endpoint.ws index 73ba58475..ebb7d7e38 100644 --- a/types/endpoint.ws +++ b/types/endpoint.ws @@ -24,6 +24,6 @@ type Todos { date: Date } -endpoint GetTodos GET /todos { +endpoint GetTodos GET /todos -> { 200 -> Todos[] }