From d4e4ef3cdd5a1bf70f365b2cd571b73894718e36 Mon Sep 17 00:00:00 2001 From: Jerre van Veluw Date: Sat, 18 Nov 2023 00:12:39 +0100 Subject: [PATCH] feat: add query params and headers to wirespec language (#127) --- Makefile | 3 + scripts/image.sh | 7 +- scripts/jvm.sh | 10 ++ scripts/test.sh | 14 +-- src/compiler/cli/build.gradle.kts | 14 ++- .../wirespec/compiler/core/LanguageSpec.kt | 2 + .../compiler/core/parse/EndpointParser.kt | 41 +++++++- .../compiler/core/parse/TypeParser.kt | 30 +++--- .../core/tokenize/types/TokenTypes.kt | 1 + .../compiler/core/parse/ParseEndpointTest.kt | 76 +++++++++++++- .../core/tokenize/TokenizeEndpointTest.kt | 98 ++++++++++++------- .../compiler/core/tokenize/TokenizeTest.kt | 36 +++++++ .../intellij-plugin/src/main/kotlin/Lexer.kt | 2 + .../intellij-plugin/src/main/kotlin/Types.kt | 1 + 14 files changed, 259 insertions(+), 76 deletions(-) create mode 100755 scripts/jvm.sh create mode 100644 src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/tokenize/TokenizeTest.kt diff --git a/Makefile b/Makefile index ca76f195..75a02221 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,9 @@ mac: linux: $(shell pwd)/scripts/linux.sh +jvm: + $(shell pwd)/scripts/jvm.sh + example: $(shell pwd)/scripts/example.sh diff --git a/scripts/image.sh b/scripts/image.sh index c7768e30..bbce39f6 100755 --- a/scripts/image.sh +++ b/scripts/image.sh @@ -1,16 +1,11 @@ #!/usr/bin/env bash -buildNothing=false archSpecific="" if [[ $(uname -m) = arm64 ]]; then archSpecific="--platform=linux/amd64" fi -if [[ $WIRESPEC_BUILD_MAC != true ]]; then - buildNothing=true -fi - -if [[ $WIRESPEC_BUILD_ALL = true || $WIRESPEC_BUILD_LINUX = true || $buildNothing = true ]]; then +if [[ $WIRESPEC_BUILD_ALL = true || $WIRESPEC_BUILD_LINUX = true ]]; then docker build $archSpecific -t wirespec . fi diff --git a/scripts/jvm.sh b/scripts/jvm.sh new file mode 100755 index 00000000..6b295e0f --- /dev/null +++ b/scripts/jvm.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash + +export WIRESPEC_BUILD_JVM=true + +dir="$(dirname -- "$0")" + +"$dir"/build.sh && + "$dir"/image.sh && + "$dir"/test.sh && + "$dir"/example.sh diff --git a/scripts/test.sh b/scripts/test.sh index 62cbe28d..c4f8a0ae 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -12,7 +12,7 @@ if [[ $(uname -m) = arm64 ]]; then archSpecific="--platform=linux/amd64" fi -if [[ $WIRESPEC_BUILD_MAC != true ]]; then +if [[ $WIRESPEC_BUILD_JVM != true ]]; then buildNothing=true fi @@ -22,15 +22,17 @@ if [[ $WIRESPEC_BUILD_ALL = true || $WIRESPEC_BUILD_MAC = true ]]; then ./src/compiler/$artifactName/build/bin/$macosArch/releaseExecutable/$artifactName.kexe -l Java -l Kotlin -l Scala -l TypeScript -l Wirespec -p "community.flock.openapi.generated" -a v2 "$(pwd)"/types/petstore.json fi -if [[ $WIRESPEC_BUILD_ALL = true || $WIRESPEC_BUILD_LINUX = true || $buildNothing = true ]]; then +if [[ $WIRESPEC_BUILD_ALL = true || $WIRESPEC_BUILD_LINUX = true ]]; then echo "Test docker image" docker run $archSpecific --rm -it -v "$(pwd)"/types:/app/types wirespec fi +if [[ $WIRESPEC_BUILD_ALL = true || $WIRESPEC_BUILD_JVM = true || $buildNothing = true ]]; then + echo "Test JVM artifact" + java -jar src/compiler/$artifactName/build/libs/$artifactName-$version-all.jar -l Java -l Kotlin -l Scala -l TypeScript -l Wirespec -p "community.flock.wirespec.generated" "$(pwd)"/types + java -jar src/compiler/$artifactName/build/libs/$artifactName-$version-all.jar -l Java -l Kotlin -l Scala -l TypeScript -l Wirespec -p "community.flock.openapi.generated" -a v2 "$(pwd)"/types/petstore.json +fi + echo "Test Node.js artifact" node build/js/packages/wirespec-src-compiler-$artifactName/kotlin/wirespec-src-compiler-$artifactName.js -l Java -l Kotlin -l Scala -l TypeScript -l Wirespec -p "community.flock.wirespec.generated" "$(pwd)"/types node build/js/packages/wirespec-src-compiler-$artifactName/kotlin/wirespec-src-compiler-$artifactName.js -l Java -l Kotlin -l Scala -l TypeScript -l Wirespec -p "community.flock.openapi.generated" -a v2 "$(pwd)"/types/petstore.json - -echo "Test JVM artifact" -java -jar src/compiler/$artifactName/build/libs/$artifactName-$version-all.jar -l Java -l Kotlin -l Scala -l TypeScript -l Wirespec -p "community.flock.wirespec.generated" "$(pwd)"/types -java -jar src/compiler/$artifactName/build/libs/$artifactName-$version-all.jar -l Java -l Kotlin -l Scala -l TypeScript -l Wirespec -p "community.flock.openapi.generated" -a v2 "$(pwd)"/types/petstore.json diff --git a/src/compiler/cli/build.gradle.kts b/src/compiler/cli/build.gradle.kts index 347c022c..40c78bee 100644 --- a/src/compiler/cli/build.gradle.kts +++ b/src/compiler/cli/build.gradle.kts @@ -24,8 +24,9 @@ kotlin { val buildAll = "WIRESPEC_BUILD_ALL".fromEnv() val buildMacX86 = buildAll || "WIRESPEC_BUILD_MAC_X86".fromEnv() val buildMacArm = buildAll || "WIRESPEC_BUILD_MAC_ARM".fromEnv() - val buildNothing = !buildMacX86 && !buildMacArm - val buildLinux = buildAll || "WIRESPEC_BUILD_LINUX".fromEnv() || buildNothing + val buildLinux = buildAll || "WIRESPEC_BUILD_LINUX".fromEnv() + val buildNothing = !buildMacX86 && !buildMacArm && !buildLinux + val buildJvm = buildAll || "WIRESPEC_BUILD_JVM".fromEnv() || buildNothing if (buildMacX86) macosX64 { build() } if (buildMacArm) macosArm64 { build() } @@ -84,12 +85,15 @@ kotlin { dependsOn(desktopMain) } } - val jsMain by getting { - dependsOn(commonMain) + if (buildJvm) { + val jvmMain by getting { + dependsOn(commonMain) + } } - val jvmMain by getting { + val jsMain by getting { dependsOn(commonMain) } + } } 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 9fe43dd0..18f336c0 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 @@ -8,6 +8,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.ForwardSlash +import community.flock.wirespec.compiler.core.tokenize.types.Hash 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 @@ -45,6 +46,7 @@ object Wirespec : LanguageSpec { Regex("^:") to Colon, Regex("^,") to Comma, Regex("^\\?") to QuestionMark, + Regex("^#") to Hash, Regex("^\\[\\]") to Brackets, Regex("^String") to WsString, Regex("^Integer") to WsInteger, 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 b614336f..621951dc 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 @@ -14,9 +14,11 @@ 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.ForwardSlash +import community.flock.wirespec.compiler.core.tokenize.types.Hash 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.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.WirespecType @@ -28,6 +30,8 @@ import community.flock.wirespec.compiler.utils.Logger class EndpointParser(logger: Logger) : AbstractParser(logger) { + private val typeParser = TypeParser(logger) + fun TokenProvider.parseEndpoint(): Either = either { eatToken().bind() token.log() @@ -61,10 +65,39 @@ class EndpointParser(logger: Logger) : AbstractParser(logger) { } val segments = mutableListOf().apply { - while (token.type !is Arrow) { + while (token.type !is QuestionMark && token.type !is Hash && token.type !is Arrow) { add(parseEndpointSegments().bind()) } - }.also { eatToken().bind() } + } + + val queryParams = when (token.type) { + is QuestionMark -> { + eatToken().bind() + when (token.type) { + is LeftCurly -> with(typeParser) { parseTypeShape().bind() }.value + else -> raise(WrongTokenException(token)) + } + } + + else -> emptyList() + } + + val headers = when (token.type) { + is Hash -> { + eatToken().bind() + when (token.type) { + is LeftCurly -> with(typeParser) { parseTypeShape().bind() }.value + else -> raise(WrongTokenException(token)) + } + } + + else -> emptyList() + } + + when (token.type) { + is Arrow -> eatToken().bind() + else -> raise(WrongTokenException(token)) + } when (token.type) { is LeftCurly -> Unit @@ -77,8 +110,8 @@ class EndpointParser(logger: Logger) : AbstractParser(logger) { name = name, method = method, path = segments, - query = emptyList(), - headers = emptyList(), + query = queryParams, + headers = headers, cookies = emptyList(), requests = requests, responses = responses, diff --git a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/parse/TypeParser.kt b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/parse/TypeParser.kt index 85e11a99..3daf0aa2 100644 --- a/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/parse/TypeParser.kt +++ b/src/compiler/core/src/commonMain/kotlin/community/flock/wirespec/compiler/core/parse/TypeParser.kt @@ -31,21 +31,7 @@ class TypeParser(logger: Logger) : AbstractParser(logger) { } } - private fun TokenProvider.parseTypeDefinition(typeName: String) = either { - eatToken().bind() - token.log() - when (token.type) { - is LeftCurly -> Type(typeName, parseTypeShape().bind()) - else -> raise(WrongTokenException(token).also { eatToken().bind() }) - }.also { - when (token.type) { - is RightCurly -> eatToken().bind() - else -> raise(WrongTokenException(token).also { eatToken().bind() }) - } - } - } - - private fun TokenProvider.parseTypeShape() = either { + fun TokenProvider.parseTypeShape(): Either = either { eatToken().bind() token.log() when (token.type) { @@ -61,9 +47,23 @@ class TypeParser(logger: Logger) : AbstractParser(logger) { } else -> raise(WrongTokenException(token).also { eatToken().bind() }) + }.also { + when (token.type) { + is RightCurly -> eatToken().bind() + else -> raise(WrongTokenException(token).also { eatToken().bind() }) + } }.let(Type::Shape) } + private fun TokenProvider.parseTypeDefinition(typeName: String) = either { + eatToken().bind() + token.log() + when (token.type) { + is LeftCurly -> Type(typeName, parseTypeShape().bind()) + else -> raise(WrongTokenException(token).also { eatToken().bind() }) + } + } + private fun TokenProvider.parseField(identifier: Type.Shape.Field.Identifier) = either { eatToken().bind() token.log() 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 e2c0bc5b..ac47146c 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 Hash : TokenType data object ForwardSlash : TokenType data object Brackets : TokenType data object CustomValue : TokenType 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 d2be154b..e032ed38 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 @@ -7,6 +7,8 @@ import community.flock.wirespec.compiler.core.parse.nodes.Endpoint.Method.POST 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.parse.nodes.Type.Shape.Field.Reference.Primitive +import community.flock.wirespec.compiler.core.parse.nodes.Type.Shape.Field.Reference.Primitive.Type.String import community.flock.wirespec.compiler.core.tokenize.tokenize import community.flock.wirespec.compiler.utils.noLogger import io.kotest.assertions.arrow.core.shouldBeRight @@ -22,7 +24,7 @@ class ParseEndpointTest { private fun parser() = Parser(noLogger) @Test - fun testEndpointParserWithCorrectInput() { + fun testEndpointParser() { val source = """ endpoint GetTodos GET /todos -> { 200 -> Todo[] @@ -45,7 +47,7 @@ class ParseEndpointTest { } @Test - fun testPathParamsParserWithCorrectInput() { + fun testPathParamsParser() { val source = """ endpoint PostTodo POST Todo /todos -> { 200 -> Todo @@ -75,7 +77,7 @@ class ParseEndpointTest { } @Test - fun testRequestBodyParserWithCorrectInput() { + fun testRequestBodyParser() { val source = """ endpoint GetTodo GET /todos/{id: String} -> { 200 -> Todo @@ -95,8 +97,8 @@ class ParseEndpointTest { path shouldBe listOf( Literal("todos"), Endpoint.Segment.Param( identifier = Identifier("id"), - reference = Reference.Primitive( - type = Reference.Primitive.Type.String, + reference = Primitive( + type = String, isIterable = false, isMap = false, ) @@ -105,4 +107,68 @@ class ParseEndpointTest { requests.shouldBeEmpty() } } + + @Test + fun testQueryParamsParser() { + val source = """ + endpoint GetTodos GET /todos?{name: String, date: String} -> { + 200 -> Todo[] + } + + """.trimIndent() + + Wirespec.tokenize(source) + .let(parser()::parse) + .shouldBeRight() + .also { it.size shouldBe 1 } + .first() + .shouldBeInstanceOf() + .query.shouldNotBeEmpty().also { it.size shouldBe 2 }.take(2).let { + val (one, two) = it + one.run { + identifier.value shouldBe "name" + reference.shouldBeInstanceOf().type shouldBe String + isNullable shouldBe false + } + two.run { + identifier.value shouldBe "date" + reference.shouldBeInstanceOf().type shouldBe String + isNullable shouldBe false + } + } + + + } + + @Test + fun testHeadersParser() { + val source = """ + endpoint GetTodos GET /todos#{name: String, date: String} -> { + 200 -> Todo[] + } + + """.trimIndent() + + Wirespec.tokenize(source) + .let(parser()::parse) + .shouldBeRight() + .also { it.size shouldBe 1 } + .first() + .shouldBeInstanceOf() + .headers.shouldNotBeEmpty().also { it.size shouldBe 2 }.take(2).let { + val (one, two) = it + one.run { + identifier.value shouldBe "name" + reference.shouldBeInstanceOf().type shouldBe String + isNullable shouldBe false + } + two.run { + identifier.value shouldBe "date" + reference.shouldBeInstanceOf().type shouldBe String + isNullable shouldBe false + } + } + + + } } 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 f42cb56e..4063744e 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 @@ -4,47 +4,28 @@ 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.Comma 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.Hash 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.QuestionMark 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.collections.shouldNotBeEmpty +import io.kotest.matchers.collections.shouldNotContain import io.kotest.matchers.shouldBe import kotlin.test.Test class TokenizeEndpointTest { - @Test - fun testEmptySource() { - val source = "" - - val expected = listOf(StartOfProgram, EndOfProgram) - - Wirespec.tokenize(source) - .also { it.size shouldBe expected.size } - .onEachIndexed { index, token -> token.type shouldBe expected[index] } - } - - @Test - fun testSourceLengthOfOneCharacterSource() { - val source = "t" - - val expected = listOf(CustomValue, EndOfProgram) - - Wirespec.tokenize(source).removeWhiteSpace() - .also { it.size shouldBe expected.size } - .onEachIndexed { index, token -> token.type shouldBe expected[index] } - } - @Test fun testStatusCodeTokenize() { val source = """ @@ -60,6 +41,7 @@ class TokenizeEndpointTest { ) Wirespec.tokenize(source).removeWhiteSpace() + .shouldNotBeEmpty() .also { it.size shouldBe expected.size } .onEachIndexed { index, token -> token.type shouldBe expected[index] } } @@ -80,17 +62,17 @@ class TokenizeEndpointTest { RightCurly, EndOfProgram, ) - Wirespec.tokenize(source).removeWhiteSpace().run { - size shouldBe expected.size - map { it.type } shouldNotContain Invalid - onEachIndexed { index, token -> token.type shouldBe expected[index] } - } + Wirespec.tokenize(source).removeWhiteSpace() + .shouldNotBeEmpty() + .also { it.size shouldBe expected.size } + .map { it.type }.shouldNotContain(Invalid) + .onEachIndexed { index, tokenType -> tokenType shouldBe expected[index] } } @Test fun testPOSTWithBodyTokenizer() { val source = """ - endpoint PostTodos Todo POST /todos -> { + endpoint PostTodo Todo POST /todos -> { 200 -> Todo } @@ -101,10 +83,56 @@ class TokenizeEndpointTest { StatusCode, Arrow, CustomType, RightCurly, EndOfProgram, ) - Wirespec.tokenize(source).removeWhiteSpace().run { - size shouldBe expected.size - map { it.type } shouldNotContain Invalid - onEachIndexed { index, token -> token.type shouldBe expected[index] } - } + Wirespec.tokenize(source).removeWhiteSpace() + .shouldNotBeEmpty() + .also { it.size shouldBe expected.size } + .map { it.type }.shouldNotContain(Invalid) + .onEachIndexed { index, tokenType -> tokenType shouldBe expected[index] } + } + + @Test + fun testQueryParamsTokenizer() { + val source = """ + endpoint GetTodos GET /todos + ?{name: String, date: String} -> { + 200 -> Todo[] + } + + """.trimIndent() + + val expected = listOf( + WsEndpointDef, CustomType, Method, Path, QuestionMark, LeftCurly, CustomValue, Colon, + WsString, Comma, CustomValue, Colon, WsString, RightCurly, Arrow, LeftCurly, + StatusCode, Arrow, CustomType, Brackets, RightCurly, EndOfProgram, + ) + + Wirespec.tokenize(source).removeWhiteSpace() + .shouldNotBeEmpty() + .also { it.size shouldBe expected.size } + .map { it.type }.shouldNotContain(Invalid) + .onEachIndexed { index, tokenType -> tokenType shouldBe expected[index] } + } + + @Test + fun testHeadersTokenizer() { + val source = """ + endpoint GetTodos GET /todos + #{version: String, accept: String} -> { + 200 -> Todo[] + } + + """.trimIndent() + + val expected = listOf( + WsEndpointDef, CustomType, Method, Path, Hash, LeftCurly, CustomValue, Colon, + WsString, Comma, CustomValue, Colon, WsString, RightCurly, Arrow, LeftCurly, + StatusCode, Arrow, CustomType, Brackets, RightCurly, EndOfProgram, + ) + + Wirespec.tokenize(source).removeWhiteSpace() + .shouldNotBeEmpty() + .also { it.size shouldBe expected.size } + .map { it.type }.shouldNotContain(Invalid) + .onEachIndexed { index, tokenType -> tokenType shouldBe expected[index] } } } diff --git a/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/tokenize/TokenizeTest.kt b/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/tokenize/TokenizeTest.kt new file mode 100644 index 00000000..9f6169ea --- /dev/null +++ b/src/compiler/core/src/commonTest/kotlin/community/flock/wirespec/compiler/core/tokenize/TokenizeTest.kt @@ -0,0 +1,36 @@ +package community.flock.wirespec.compiler.core.tokenize + +import community.flock.wirespec.compiler.core.Wirespec +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.StartOfProgram +import io.kotest.matchers.collections.shouldNotBeEmpty +import io.kotest.matchers.shouldBe +import kotlin.test.Test + +class TokenizeTest { + + @Test + fun testEmptySource() { + val source = "" + + val expected = listOf(StartOfProgram, EndOfProgram) + + Wirespec.tokenize(source) + .shouldNotBeEmpty() + .also { it.size shouldBe expected.size } + .onEachIndexed { index, token -> token.type shouldBe expected[index] } + } + + @Test + fun testSourceLengthOfOneCharacterSource() { + val source = "t" + + val expected = listOf(CustomValue, EndOfProgram) + + Wirespec.tokenize(source).removeWhiteSpace() + .shouldNotBeEmpty() + .also { it.size shouldBe expected.size } + .onEachIndexed { index, token -> token.type shouldBe expected[index] } + } +} diff --git a/src/lsp/intellij-plugin/src/main/kotlin/Lexer.kt b/src/lsp/intellij-plugin/src/main/kotlin/Lexer.kt index 94cd9b1e..792ea622 100644 --- a/src/lsp/intellij-plugin/src/main/kotlin/Lexer.kt +++ b/src/lsp/intellij-plugin/src/main/kotlin/Lexer.kt @@ -12,6 +12,7 @@ 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.Hash 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 @@ -65,6 +66,7 @@ class Lexer : IntellijLexer() { is WsString -> Types.STRING is LeftCurly -> Types.LEFT_CURLY is QuestionMark -> Types.QUESTION_MARK + is Hash -> Types.HASH is RightCurly -> Types.RIGHT_CURLY is EndOfProgram -> Types.END_OF_PROGRAM is Invalid -> Types.INVALID diff --git a/src/lsp/intellij-plugin/src/main/kotlin/Types.kt b/src/lsp/intellij-plugin/src/main/kotlin/Types.kt index 28029f73..372fb232 100644 --- a/src/lsp/intellij-plugin/src/main/kotlin/Types.kt +++ b/src/lsp/intellij-plugin/src/main/kotlin/Types.kt @@ -27,6 +27,7 @@ interface Types { val LEFT_CURLY = ElementType("LEFT_CURLY") val RIGHT_CURLY = ElementType("RIGHT_CURLY") val QUESTION_MARK = ElementType("QUESTION_MARK") + val HASH = ElementType("HASH") val BRACKETS = ElementType("BRACKETS") val WHITE_SPACE = ElementType("WHITE_SPACE") val END_OF_PROGRAM = ElementType("END_OF_PROGRAM")