diff --git a/Bitfile b/Bitfile index 65623631a9..18a13f3717 100644 --- a/Bitfile +++ b/Bitfile @@ -31,9 +31,6 @@ KT_RUNTIME_IN = kotlin-runtime/ftl-runtime/**/*.{kt,kts} pom.xml kotlin-runtime/ KT_RUNTIME_OUT = kotlin-runtime/ftl-runtime/target/ftl-runtime-1.0-SNAPSHOT.jar KT_RUNTIME_RUNNER_TEMPLATE_OUT = build/template/ftl/jars/ftl-runtime.jar -KT_GENERATOR_IN = kotlin-runtime/ftl-generator/**/*.{kt,kts} pom.xml kotlin-runtime/ftl-runtime/**/pom.xml %{KT_RUNTIME_OUT} -KT_GENERATOR_OUT = kotlin-runtime/ftl-generator/target/ftl-generator-1.0-SNAPSHOT.jar - CLIENT_IN = frontend/src/**/* CLIENT_OUT = frontend/dist/index.html NPM_IN = frontend/package{,-lock}.json @@ -119,12 +116,6 @@ kotlin-runtime/external-module-template.zip: kotlin-runtime/external-module-temp mvn -B -pl :ftl-runtime install +clean: mvn -B -pl :ftl-runtime clean -%{KT_GENERATOR_OUT}: %{KT_GENERATOR_IN} - build: - mvn -B -N install - mvn -B -pl :ftl-generator install - +clean: mvn -B -pl :ftl-generator clean - %(dirname %{KT_RUNTIME_RUNNER_TEMPLATE_OUT})%: build: install -m 0700 -d %{OUT} diff --git a/examples/kotlin/pom.xml b/examples/kotlin/pom.xml index 812e162f79..7cd8e9adc2 100644 --- a/examples/kotlin/pom.xml +++ b/examples/kotlin/pom.xml @@ -115,31 +115,6 @@ - - - org.codehaus.mojo - exec-maven-plugin - 3.0.0 - - - initialize - - exec - - - java - - -jar - target/dependency/ftl-generator.jar - --endpoint=${ftlEndpoint} - --dest=${project.build.directory} - --module=${ftlModuleName} - --module-client-suffix=ModuleClient - - - - - org.codehaus.mojo diff --git a/kotlin-runtime/ftl-generator/pom.xml b/kotlin-runtime/ftl-generator/pom.xml deleted file mode 100644 index 8db81a8dcb..0000000000 --- a/kotlin-runtime/ftl-generator/pom.xml +++ /dev/null @@ -1,155 +0,0 @@ - - - 4.0.0 - - - xyz.block - ftl - 1.0-SNAPSHOT - ../../pom.xml - - - ftl-generator - jar - - ${project.groupId}:${project.artifactId} - - - ${basedir}/../.. - false - - - - - com.squareup - kotlinpoet-jvm - 1.16.0 - - - ${project.groupId} - ftl-runtime - ${project.version} - - - com.github.ajalt.clikt - clikt-jvm - 4.2.2 - - - com.squareup.wire - wire-runtime-jvm - - - com.squareup.wire - wire-grpc-server - - - com.squareup.wire - wire-grpc-client-jvm - - - org.jetbrains.kotlin - kotlin-stdlib - - - io.grpc - grpc-protobuf - - - io.grpc - grpc-stub - - - - - - - org.apache.maven.plugins - maven-shade-plugin - - - shade-jar - package - - shade - - - false - - - xyz.block.ftl.generator.MainKt - - - false - - - - - - org.apache.maven.plugins - maven-surefire-plugin - - - kotlin-maven-plugin - org.jetbrains.kotlin - - - org.apache.maven.plugins - maven-compiler-plugin - - 11 - 11 - - - - - org.apache.maven.plugins - maven-dependency-plugin - - - - org.codehaus.mojo - exec-maven-plugin - - - org.codehaus.mojo - build-helper-maven-plugin - - - - - - - release - - - - org.apache.maven.plugins - maven-shade-plugin - - - shade-jar - - true - - - - - - org.codehaus.mojo - flatten-maven-plugin - - - flatten - package - - - - - - - - \ No newline at end of file diff --git a/kotlin-runtime/ftl-generator/src/main/kotlin/xyz/block/ftl/generator/FTLClient.kt b/kotlin-runtime/ftl-generator/src/main/kotlin/xyz/block/ftl/generator/FTLClient.kt deleted file mode 100644 index 1e6dbd2099..0000000000 --- a/kotlin-runtime/ftl-generator/src/main/kotlin/xyz/block/ftl/generator/FTLClient.kt +++ /dev/null @@ -1,48 +0,0 @@ -package xyz.block.ftl.generator - -import com.squareup.wire.GrpcClient -import kotlinx.coroutines.channels.ReceiveChannel -import kotlinx.coroutines.channels.SendChannel -import okhttp3.OkHttpClient -import okhttp3.Protocol -import xyz.block.ftl.v1.ControllerServiceClient -import xyz.block.ftl.v1.GetSchemaRequest -import xyz.block.ftl.v1.PullSchemaRequest -import xyz.block.ftl.v1.PullSchemaResponse -import xyz.block.ftl.v1.schema.Schema -import java.net.ConnectException -import java.time.Duration - -internal class FTLClient(ftlEndpoint: String) { - private var grpcClient: GrpcClient - private lateinit var sendSchemaChannel: SendChannel - private lateinit var receiveSchemaChannel: ReceiveChannel - - init { - grpcClient = GrpcClient.Builder() - .client( - OkHttpClient.Builder() - .readTimeout(Duration.ofSeconds(10)) - .writeTimeout(Duration.ofSeconds(10)) - .callTimeout(Duration.ofSeconds(10)) - .protocols(listOf(Protocol.H2_PRIOR_KNOWLEDGE)) - .addInterceptor { chain -> - try { - chain.proceed(chain.request()) - } catch (e: ConnectException) { - throw ConnectException( - "Unable to connect to FTL Controller at: $ftlEndpoint. Is it running?" - ) - } - } - .build() - ) - .baseUrl(ftlEndpoint) - .build() - } - - fun getSchema(): Schema? { - val client = grpcClient.create(ControllerServiceClient::class) - return client.GetSchema().executeBlocking(GetSchemaRequest()).schema - } -} diff --git a/kotlin-runtime/ftl-generator/src/main/kotlin/xyz/block/ftl/generator/ModuleGenerator.kt b/kotlin-runtime/ftl-generator/src/main/kotlin/xyz/block/ftl/generator/ModuleGenerator.kt deleted file mode 100644 index 9f33cf8784..0000000000 --- a/kotlin-runtime/ftl-generator/src/main/kotlin/xyz/block/ftl/generator/ModuleGenerator.kt +++ /dev/null @@ -1,238 +0,0 @@ -package xyz.block.ftl.generator - -import com.squareup.kotlinpoet.* -import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy -import xyz.block.ftl.Context -import xyz.block.ftl.HttpIngress -import xyz.block.ftl.v1.schema.* -import java.io.File -import java.nio.file.Path -import java.nio.file.attribute.PosixFilePermission -import kotlin.io.path.createDirectories -import kotlin.io.path.setPosixFilePermissions -import kotlin.io.path.writeText - -class ModuleGenerator { - fun run(schema: Schema, outputDirectory: File, module: String, moduleClientSuffix: String) { - val fqOutputDir = outputDirectory.absolutePath - prepareFtlRoot(fqOutputDir, module) - val sourcesDest = File(fqOutputDir, "generated-sources") - Path.of(sourcesDest.path).createDirectories() - schema.modules.filter { it.name != module }.forEach { - val file = generateModule(it, moduleClientSuffix) - file.writeTo(sourcesDest) - - println("Generated module: ${fqOutputDir}/generated-sources/ftl/${it.name}/${file.name}.kt") - } - } - - internal fun generateModule(module: Module, moduleClientSuffix: String = DEFAULT_MODULE_CLIENT_SUFFIX): FileSpec { - val namespace = "ftl.${module.name}" - val filename = module.name.replaceFirstChar(Char::titlecase) + moduleClientSuffix - val file = FileSpec.builder(namespace, filename) - .addFileComment("Code generated by FTL-Generator, do not edit.") - - module.comments.let { - file.addFileComment("\n") - file.addFileComment(it.joinToString("\n")) - } - - val emptyData = mutableSetOf() - val types = module.decls.mapNotNull { it.data_ } - types.forEach { - if (namespace == "ftl.builtin" && it.name == "Empty") { - file.addType( - TypeSpec.classBuilder(it.name) - .addKdoc(it.comments.joinToString("\n")) - .build() - ) - } else if (it.fields.isEmpty()) { - emptyData.add("${namespace}.${it.name}") - } else { - file.addType(buildDataClass(it, namespace)) - } - } - - val verbs = module.decls.mapNotNull { it.verb } - verbs.forEach { file.addFunction(buildVerbFunction(namespace, emptyData, it)) } - - return file.build() - } - - private fun buildDataClass(type: Data, namespace: String): TypeSpec { - val dataClassBuilder = TypeSpec.classBuilder(type.name) - .addModifiers(KModifier.DATA) - .addTypeVariables(type.typeParameters.map { TypeVariableName(it.name) }) - .addKdoc(type.comments.joinToString("\n")) - - val dataConstructorBuilder = FunSpec.constructorBuilder() - type.fields.forEach { field -> - dataClassBuilder.addKdoc(field.comments.joinToString("\n")) - field.type?.let { type -> - var parameter = ParameterSpec - .builder(field.name, getTypeClass(type, namespace)) - if (type.optional != null) { - parameter = parameter.defaultValue("null") - } - dataConstructorBuilder.addParameter(parameter.build()) - dataClassBuilder.addProperty( - PropertySpec.builder(field.name, getTypeClass(type, namespace)).initializer(field.name).let { - if (field.jsonAlias != "") { - it.addAnnotation( - AnnotationSpec.builder(xyz.block.ftl.Json::class).addMember("%S", field.jsonAlias).build() - ) - } else { - it - } - }.build() - ) - } - } - - dataClassBuilder.primaryConstructor(dataConstructorBuilder.build()) - - return dataClassBuilder.build() - } - - private fun buildVerbFunction(namespace: String, emptyData: Set, verb: Verb): FunSpec { - val verbFunBuilder = - FunSpec.builder(verb.name) - .addKdoc(verb.comments.joinToString("\n")) - .addAnnotation(AnnotationSpec.builder(xyz.block.ftl.Verb::class).build()) - .addAnnotation(AnnotationSpec.builder(xyz.block.ftl.Ignore::class).build()) - - verb.metadata.forEach { metadata -> - metadata.ingress?.let { - verbFunBuilder.addAnnotation( - AnnotationSpec.builder(HttpIngress::class) - .addMember("%T", ClassName("xyz.block.ftl.Method", it.method.replaceBefore(".", ""))) - .addMember("%S", ingressPathString(it.path)) - .build() - ) - } - } - - verbFunBuilder.addParameter("context", Context::class) - val emptyDataRef = getTypeClass(Type(dataRef = DataRef(name = "Empty")), "ftl.builtin") - - verb.request?.let { - verbFunBuilder.addParameter( - "req", - if (emptyData.contains("${namespace}.${it.dataRef?.name}")) { - emptyDataRef - } else { - getTypeClass(it, namespace) - } - ) - } - - verb.response?.let { - verbFunBuilder.returns( - if (emptyData.contains("${namespace}.${it.dataRef?.name}")) { - emptyDataRef - } else { - getTypeClass(it, namespace) - } - ) - } - - val message = - "Verb stubs should not be called directly, instead use context.call(::${verb.name}, ...)" - verbFunBuilder.addCode("""throw NotImplementedError(%S)""", message) - - return verbFunBuilder.build() - } - - private fun ingressPathString(components: List): String { - return "/" + components.joinToString("/") { component -> - when { - component.ingressPathLiteral != null -> component.ingressPathLiteral.text - component.ingressPathParameter != null -> "{${component.ingressPathParameter.name}}" - else -> throw IllegalArgumentException("Unknown ingress path component") - } - } - } - - private fun getTypeClass(type: Type, namespace: String): TypeName { - return when { - type.int != null -> ClassName("kotlin", "Long") - type.float != null -> ClassName("kotlin", "Float") - type.string != null -> ClassName("kotlin", "String") - type.bytes != null -> ClassName("kotlin", "ByteArray") - type.bool != null -> ClassName("kotlin", "Boolean") - type.time != null -> ClassName("java.time", "OffsetDateTime") - type.unit != null -> ClassName("kotlin", "Unit") - type.any != null -> ClassName("kotlin", "Any") - type.array != null -> { - val element = type.array?.element ?: throw IllegalArgumentException( - "Missing element type in kotlin array generator" - ) - val elementType = getTypeClass(element, namespace) - val arrayList = ClassName("kotlin.collections", "ArrayList") - arrayList.parameterizedBy(elementType) - } - - type.map != null -> { - val map = ClassName("kotlin.collections", "Map") - val key = - type.map?.key ?: throw IllegalArgumentException("Missing map key in kotlin map generator") - val value = type.map?.value_ ?: throw IllegalArgumentException( - "Missing map value in kotlin map generator" - ) - map.parameterizedBy(getTypeClass(key, namespace), getTypeClass(value, namespace)) - } - - type.dataRef != null -> { - val module = if (type.dataRef.module.isEmpty()) namespace else "ftl.${type.dataRef.module}" - ClassName(module, type.dataRef.name).let { className -> - if (type.dataRef.typeParameters.isNotEmpty()) { - className.parameterizedBy(type.dataRef.typeParameters.map { getTypeClass(it, namespace) }) - } else { - className - } - } - } - - type.optional != null -> { - val wrapped = type.optional.type ?: throw IllegalArgumentException( - "Missing wrapped type in kotlin optional generator" - ) - return getTypeClass(wrapped, namespace).copy(nullable = true) - } - - else -> throw IllegalArgumentException("Unknown type in kotlin generator") - } - } - - private fun prepareFtlRoot(buildDir: String, module: String) { - Path.of(buildDir).createDirectories() - - Path.of(buildDir, "detekt.yml").writeText( - """ - SchemaExtractorRuleSet: - ExtractSchemaRule: - active: true - output: ${buildDir} - """.trimIndent() - ) - - val mainFile = Path.of(buildDir, "main") - mainFile.writeText( - """ - #!/bin/bash - exec java -cp "classes:$(cat classpath.txt)" xyz.block.ftl.main.MainKt - """.trimIndent(), - ) - mainFile.setPosixFilePermissions( - setOf( - PosixFilePermission.OWNER_EXECUTE, - PosixFilePermission.OWNER_READ, - PosixFilePermission.OWNER_WRITE - ) - ) - } - - companion object { - const val DEFAULT_MODULE_CLIENT_SUFFIX = "Module" - } -} diff --git a/kotlin-runtime/ftl-generator/src/main/kotlin/xyz/block/ftl/generator/main.kt b/kotlin-runtime/ftl-generator/src/main/kotlin/xyz/block/ftl/generator/main.kt deleted file mode 100644 index feb9070097..0000000000 --- a/kotlin-runtime/ftl-generator/src/main/kotlin/xyz/block/ftl/generator/main.kt +++ /dev/null @@ -1,28 +0,0 @@ -package xyz.block.ftl.generator - -import com.github.ajalt.clikt.core.CliktCommand -import com.github.ajalt.clikt.parameters.options.default -import com.github.ajalt.clikt.parameters.options.option -import com.github.ajalt.clikt.parameters.options.required -import xyz.block.ftl.generator.ModuleGenerator.Companion.DEFAULT_MODULE_CLIENT_SUFFIX -import java.io.File - -class Main : CliktCommand() { - val endpoint by option(help = "FTL endpoint.").required() - val dest by option(help = "Destination directory for generated code.").required() - val module by option(help = "The FTL module name we're working on.").required() - val moduleClientSuffix by option( - help = "The suffix appended to FTL-generated client classes for other modules in this cluster." - ).default(DEFAULT_MODULE_CLIENT_SUFFIX) - - override fun run() { - val client = FTLClient(endpoint) - val schema = client.getSchema()!! - val outputDirectory = File(dest) - outputDirectory.deleteRecursively() - val gen = ModuleGenerator() - gen.run(schema, outputDirectory, module, moduleClientSuffix) - } -} - -fun main(args: Array) = Main().main(args) diff --git a/kotlin-runtime/ftl-generator/src/test/kotlin/xyz/block/ftl/generator/ModuleGeneratorTest.kt b/kotlin-runtime/ftl-generator/src/test/kotlin/xyz/block/ftl/generator/ModuleGeneratorTest.kt deleted file mode 100644 index d5c8655adb..0000000000 --- a/kotlin-runtime/ftl-generator/src/test/kotlin/xyz/block/ftl/generator/ModuleGeneratorTest.kt +++ /dev/null @@ -1,338 +0,0 @@ -package xyz.block.ftl.generator - -import org.junit.jupiter.api.BeforeEach -import org.junit.jupiter.api.Test -import xyz.block.ftl.v1.schema.* -import xyz.block.ftl.v1.schema.Array -import xyz.block.ftl.v1.schema.Float -import xyz.block.ftl.v1.schema.Int -import xyz.block.ftl.v1.schema.Map -import xyz.block.ftl.v1.schema.String -import kotlin.test.assertEquals - -class ModuleGeneratorTest { - private lateinit var generator: ModuleGenerator - - @BeforeEach - fun setUp() { - generator = ModuleGenerator() - } - - @Test - fun `should generate basic module`() { - val file = generator.generateModule(Module(name = "test")) - val expected = """// Code generated by FTL-Generator, do not edit. -// -package ftl.test - -""" - assertEquals(expected, file.toString()) - } - - @Test - fun `should generate all Types`() { - val decls = listOf( - Decl( - data_ = Data( - name = "ParamTestData", - typeParameters = listOf(TypeParameter(name = "T")), - fields = listOf( - Field(name = "t", type = Type(dataRef = DataRef(name = "T"))), - ) - ) - ), - Decl( - data_ = Data( - comments = listOf("Response comments"), name = "TestResponse", - fields = listOf( - Field(name = "int", type = Type(int = Int())), - Field(name = "float", type = Type(float = Float())), - Field(name = "string", type = Type(string = String())), - Field(name = "bytes", type = Type(bytes = Bytes())), - Field(name = "bool", type = Type(bool = Bool())), - Field(name = "time", type = Type(time = Time())), - Field(name = "optional", type = Type(optional = Optional(type = Type(string = String())))), - Field(name = "array", type = Type(array = Array(element = Type(string = String())))), - Field( - name = "nestedArray", type = Type( - array = Array(element = Type(array = Array(element = Type(string = String())))) - ) - ), - Field( - name = "dataRefArray", type = Type( - array = Array(element = Type(dataRef = DataRef(name = "TestRequest", module = "test"))) - ) - ), - Field( - name = "map", - type = Type(map = Map(key = Type(string = String()), value_ = Type(int = Int()))) - ), - Field( - name = "nestedMap", type = Type( - map = Map( - key = Type(string = String()), - value_ = Type(map = Map(key = Type(string = String()), value_ = Type(int = Int()))) - ) - ) - ), - Field(name = "dataRef", type = Type(dataRef = DataRef(name = "TestRequest"))), - Field(name = "externalDataRef", type = Type(dataRef = DataRef(module = "other", name = "TestRequest"))), - Field(name = "any", type = Type(any = xyz.block.ftl.v1.schema.Any())), - Field( - name = "parameterizedDataRef", type = Type( - dataRef = DataRef( - name = "ParamTestData", - typeParameters = listOf(Type(dataRef = DataRef(name = "T"))) - ) - ) - ), - Field(name = "withAlias", type = Type(string = String()), jsonAlias = "a"), - ) - ) - ), - ) - val module = Module(name = "test", comments = listOf("Module comments"), decls = decls) - - val file = generator.generateModule(module) - val expected = """// Code generated by FTL-Generator, do not edit. -// Module comments -package ftl.test - -import java.time.OffsetDateTime -import kotlin.Any -import kotlin.Boolean -import kotlin.ByteArray -import kotlin.Float -import kotlin.Long -import kotlin.String -import kotlin.collections.ArrayList -import kotlin.collections.Map -import xyz.block.ftl.Json - -public data class ParamTestData( - public val t: T, -) - -/** - * Response comments - */ -public data class TestResponse( - public val int: Long, - public val float: Float, - public val string: String, - public val bytes: ByteArray, - public val bool: Boolean, - public val time: OffsetDateTime, - public val optional: String? = null, - public val array: ArrayList, - public val nestedArray: ArrayList>, - public val dataRefArray: ArrayList, - public val map: Map, - public val nestedMap: Map>, - public val dataRef: TestRequest, - public val externalDataRef: ftl.other.TestRequest, - public val any: Any, - public val parameterizedDataRef: ParamTestData, - @Json("a") - public val withAlias: String, -) -""" - assertEquals(expected, file.toString()) - } - - @Test - fun `should generate all Verbs`() { - val decls = listOf( - Decl( - verb = Verb( - name = "TestVerb", - comments = listOf("TestVerb comments"), - request = Type(dataRef = DataRef(name = "Empty", module = "builtin")), - response = Type(dataRef = DataRef(name = "Empty", module = "builtin")) - ) - ), - Decl( - verb = Verb( - name = "TestIngressVerb", - comments = listOf("TestIngressVerb comments"), - request = Type(dataRef = DataRef(name = "Empty", module = "builtin")), - response = Type(dataRef = DataRef(name = "Empty", module = "builtin")), - metadata = listOf( - Metadata( - ingress = MetadataIngress( - type = "http", - path = listOf(IngressPathComponent(ingressPathLiteral = IngressPathLiteral(text = "test"))), - method = "GET" - ) - ), - ) - ) - ), - ) - val module = Module(name = "test", comments = listOf("Module comments"), decls = decls) - val file = generator.generateModule(module) - val expected = """// Code generated by FTL-Generator, do not edit. -// Module comments -package ftl.test - -import ftl.builtin.Empty -import xyz.block.ftl.Context -import xyz.block.ftl.HttpIngress -import xyz.block.ftl.Ignore -import xyz.block.ftl.Method.GET -import xyz.block.ftl.Verb - -/** - * TestVerb comments - */ -@Verb -@Ignore -public fun TestVerb(context: Context, req: Empty): Empty = throw - NotImplementedError("Verb stubs should not be called directly, instead use context.call(::TestVerb, ...)") - -/** - * TestIngressVerb comments - */ -@Verb -@Ignore -@HttpIngress( - GET, - "/test", -) -public fun TestIngressVerb(context: Context, req: Empty): Empty = throw - NotImplementedError("Verb stubs should not be called directly, instead use context.call(::TestIngressVerb, ...)") -""" - assertEquals(expected, file.toString()) - } - - @Test - fun `builtins are handled correctly`() { - val decls = listOf( - Decl( - data_ = Data( - comments = listOf("HTTP request structure used for HTTP ingress verbs."), - name = "HttpRequest", - fields = listOf( - Field(name = "method", type = Type(string = String())), - Field(name = "path", type = Type(string = String())), - Field( - name = "pathParameters", - type = Type(map = Map(key = Type(string = String()), value_ = Type(string = String()))) - ), - Field( - name = "query", - type = Type( - map = Map( - key = Type(string = String()), - value_ = Type(array = Array(element = Type(string = String()))) - ) - ) - ), - Field( - name = "headers", - type = Type( - map = Map( - key = Type(string = String()), - value_ = Type(array = Array(element = Type(string = String()))) - ) - ) - ), - Field(name = "body", type = Type(dataRef = DataRef(name = "Body"))) - ), - typeParameters = listOf(TypeParameter(name = "Body")) - ) - ), - Decl( - data_ = Data( - comments = listOf("HTTP response structure used for HTTP ingress verbs."), - name = "HttpResponse", - fields = listOf( - Field(name = "status", type = Type(int = Int())), - Field( - name = "headers", - type = Type( - map = Map( - key = Type(string = String()), - value_ = Type(array = Array(element = Type(string = String()))) - ) - ) - ), - Field(name = "body", type = Type(dataRef = DataRef(name = "Body"))) - ), - typeParameters = listOf(TypeParameter(name = "Body")) - ) - ), - Decl(data_ = Data(name = "Empty")), - ) - val module = Module(name = "builtin", comments = listOf("Built-in types for FTL"), decls = decls) - val file = generator.generateModule(module) - val expected = """// Code generated by FTL-Generator, do not edit. -// Built-in types for FTL -package ftl.builtin - -import kotlin.Long -import kotlin.String -import kotlin.collections.ArrayList -import kotlin.collections.Map - -/** - * HTTP request structure used for HTTP ingress verbs. - */ -public data class HttpRequest( - public val method: String, - public val path: String, - public val pathParameters: Map, - public val query: Map>, - public val headers: Map>, - public val body: Body, -) - -/** - * HTTP response structure used for HTTP ingress verbs. - */ -public data class HttpResponse( - public val status: Long, - public val headers: Map>, - public val body: Body, -) - -public class Empty -""" - assertEquals(expected, file.toString()) - } - - @Test - fun `generates empty data refs`() { - val file = generator.generateModule( - Module( - name = "test", - decls = listOf( - Decl(data_ = Data(name = "EmptyRequest")), - Decl(data_ = Data(name = "EmptyResponse")), - Decl( - verb = Verb( - name = "EmptyVerb", - request = Type(dataRef = DataRef(name = "EmptyRequest")), - response = Type(dataRef = DataRef(name = "EmptyResponse")) - ) - ) - ) - ) - ) - val expected = """// Code generated by FTL-Generator, do not edit. -// -package ftl.test - -import ftl.builtin.Empty -import xyz.block.ftl.Context -import xyz.block.ftl.Ignore -import xyz.block.ftl.Verb - -@Verb -@Ignore -public fun EmptyVerb(context: Context, req: Empty): Empty = throw - NotImplementedError("Verb stubs should not be called directly, instead use context.call(::EmptyVerb, ...)") -""" - assertEquals(expected, file.toString()) - } -} diff --git a/pom.xml b/pom.xml index 2f050332f6..c30fd7e288 100644 --- a/pom.xml +++ b/pom.xml @@ -46,7 +46,6 @@ kotlin-runtime/ftl-runtime - kotlin-runtime/ftl-generator @@ -344,7 +343,6 @@ release kotlin-runtime/ftl-runtime - kotlin-runtime/ftl-generator