From 5ba8d95e8393d6dcbfe04245c67d68ec42329893 Mon Sep 17 00:00:00 2001 From: theEvilReaper Date: Wed, 10 Jan 2024 12:19:20 +0100 Subject: [PATCH 01/15] Outsource typedefs into an own structure --- .../dartpoet/code/writer/FunctionWriter.kt | 6 +----- .../dartpoet/function/FunctionBuilder.kt | 15 --------------- .../dartpoet/function/FunctionSpec.kt | 2 -- 3 files changed, 1 insertion(+), 22 deletions(-) diff --git a/src/main/kotlin/net/theevilreaper/dartpoet/code/writer/FunctionWriter.kt b/src/main/kotlin/net/theevilreaper/dartpoet/code/writer/FunctionWriter.kt index 22273079..2e53c121 100644 --- a/src/main/kotlin/net/theevilreaper/dartpoet/code/writer/FunctionWriter.kt +++ b/src/main/kotlin/net/theevilreaper/dartpoet/code/writer/FunctionWriter.kt @@ -18,12 +18,8 @@ internal class FunctionWriter : Writeable { if (spec.hasDocs) { spec.docs.forEach { writer.emitDoc(it) } } - if (spec.isTypeDef) { - writeTypeDef(spec, writer) - return - } - if (!spec.isTypeDef && spec.annotation.isNotEmpty()) { + if (spec.annotation.isNotEmpty()) { spec.annotation.forEach { it.write(writer) } writer.emit(NEW_LINE) } diff --git a/src/main/kotlin/net/theevilreaper/dartpoet/function/FunctionBuilder.kt b/src/main/kotlin/net/theevilreaper/dartpoet/function/FunctionBuilder.kt index ef7ace5f..6ad8e96a 100644 --- a/src/main/kotlin/net/theevilreaper/dartpoet/function/FunctionBuilder.kt +++ b/src/main/kotlin/net/theevilreaper/dartpoet/function/FunctionBuilder.kt @@ -26,7 +26,6 @@ class FunctionBuilder internal constructor( internal var async: Boolean = false internal var returnType: TypeName? = null internal val body: CodeBlock.Builder = CodeBlock.builder() - internal var typedef: Boolean = false internal var typeCast: TypeName? = null internal var setter: Boolean = false internal var getter: Boolean = false @@ -94,14 +93,6 @@ class FunctionBuilder internal constructor( */ fun typeCast(cast: KClass<*>) = apply { this.typeCast = cast.asTypeName() } - /** - * If the function should be generated as typedef definition. - * @param typeDef true for a typedef - */ - fun typedef(typeDef: Boolean) = apply { - this.typedef = typeDef - } - fun addCode(format: String, vararg args: Any?) = apply { body.add(format, *args) } @@ -180,12 +171,6 @@ class FunctionBuilder internal constructor( * @return the created instance */ fun build(): FunctionSpec { - // Remove typedef keyword from the list to prevent problems - if (specData.modifiers.contains(DartModifier.TYPEDEF)) { - typedef(true) - specData.modifiers.remove(DartModifier.TYPEDEF) - } - return FunctionSpec(this) } } diff --git a/src/main/kotlin/net/theevilreaper/dartpoet/function/FunctionSpec.kt b/src/main/kotlin/net/theevilreaper/dartpoet/function/FunctionSpec.kt index abc78e98..3bac2f1e 100644 --- a/src/main/kotlin/net/theevilreaper/dartpoet/function/FunctionSpec.kt +++ b/src/main/kotlin/net/theevilreaper/dartpoet/function/FunctionSpec.kt @@ -34,7 +34,6 @@ class FunctionSpec( hasAllowedModifiers(it, ALLOWED_FUNCTION_MODIFIERS, "function") }.filter { it != DartModifier.PRIVATE && it != DartModifier.PUBLIC }.toImmutableSet() internal val isPrivate = builder.specData.modifiers.contains(DartModifier.PRIVATE) - internal val isTypeDef = builder.typedef internal val typeCast = builder.typeCast internal val asSetter = builder.setter internal val isGetter = builder.getter @@ -89,7 +88,6 @@ class FunctionSpec( builder.modifiers(*this.modifiers.toTypedArray()) builder.parameters.addAll(this.parameters) builder.async = this.isAsync - builder.typedef = this.isTypeDef builder.typeCast = this.typeCast builder.setter = this.asSetter builder.getter = this.isGetter From 76e3d9e3f8dc62de5191f9fa934061f9934ba029 Mon Sep 17 00:00:00 2001 From: theEvilReaper Date: Wed, 10 Jan 2024 12:19:47 +0100 Subject: [PATCH 02/15] Add new extension method to write the typedef objects --- .../dartpoet/code/CodeWriterExtension.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/kotlin/net/theevilreaper/dartpoet/code/CodeWriterExtension.kt b/src/main/kotlin/net/theevilreaper/dartpoet/code/CodeWriterExtension.kt index 23b7fe7c..a964dc42 100644 --- a/src/main/kotlin/net/theevilreaper/dartpoet/code/CodeWriterExtension.kt +++ b/src/main/kotlin/net/theevilreaper/dartpoet/code/CodeWriterExtension.kt @@ -5,6 +5,7 @@ import net.theevilreaper.dartpoet.extension.ExtensionSpec import net.theevilreaper.dartpoet.function.FunctionSpec import net.theevilreaper.dartpoet.function.constructor.ConstructorSpec import net.theevilreaper.dartpoet.directive.Directive +import net.theevilreaper.dartpoet.function.typedef.TypeDefSpec import net.theevilreaper.dartpoet.property.consts.ConstantPropertySpec import net.theevilreaper.dartpoet.parameter.ParameterSpec import net.theevilreaper.dartpoet.property.PropertySpec @@ -199,6 +200,19 @@ fun Set.emitConstants( } } +fun List.emitTypeDefs( + codeWriter: CodeWriter, + emitBlock: (TypeDefSpec) -> Unit = { it.write(codeWriter) } +) = with(codeWriter) { + val emitNewLines = size > 1 + forEachIndexed { index, typeDefSpec -> + if (index > 0 && emitNewLines) { + emit(NEW_LINE) + } + emitBlock(typeDefSpec) + } +} + fun Set.emitProperties( codeWriter: CodeWriter, forceNewLines: Boolean = false, From 6d0cacba137ced2c699c7c040dc937644e925b9d Mon Sep 17 00:00:00 2001 From: theEvilReaper Date: Wed, 10 Jan 2024 12:20:14 +0100 Subject: [PATCH 03/15] Add structure to manage or write typedef objects --- .../dartpoet/code/writer/TypeDefWriter.kt | 30 +++++ .../function/typedef/TypeDefBuilder.kt | 104 ++++++++++++++++ .../dartpoet/function/typedef/TypeDefSpec.kt | 111 ++++++++++++++++++ 3 files changed, 245 insertions(+) create mode 100644 src/main/kotlin/net/theevilreaper/dartpoet/code/writer/TypeDefWriter.kt create mode 100644 src/main/kotlin/net/theevilreaper/dartpoet/function/typedef/TypeDefBuilder.kt create mode 100644 src/main/kotlin/net/theevilreaper/dartpoet/function/typedef/TypeDefSpec.kt diff --git a/src/main/kotlin/net/theevilreaper/dartpoet/code/writer/TypeDefWriter.kt b/src/main/kotlin/net/theevilreaper/dartpoet/code/writer/TypeDefWriter.kt new file mode 100644 index 00000000..b748f1f4 --- /dev/null +++ b/src/main/kotlin/net/theevilreaper/dartpoet/code/writer/TypeDefWriter.kt @@ -0,0 +1,30 @@ +package net.theevilreaper.dartpoet.code.writer + +import net.theevilreaper.dartpoet.DartModifier +import net.theevilreaper.dartpoet.code.CodeWriter +import net.theevilreaper.dartpoet.code.Writeable +import net.theevilreaper.dartpoet.code.emitParameters +import net.theevilreaper.dartpoet.function.typedef.TypeDefSpec +import net.theevilreaper.dartpoet.util.SEMICOLON + +class TypeDefWriter : Writeable { + override fun write(spec: TypeDefSpec, writer: CodeWriter) { + writer.emit("${DartModifier.TYPEDEF.identifier}·${spec.typeDefName}") + if (spec.typeCast != null) { + writer.emitCode("<%T>", spec.typeCast) + } + writer.emit("·=·") + writer.emitCode("%T", spec.returnType) + + if (spec.name != null) { + writer.emitCode("·%L", spec.name) + } + + if (spec.hasParameters) { + writer.emit("(") + spec.parameters.emitParameters(writer, forceNewLines = false, emitBrackets = false, emitSpace = spec.parameters.size > 1) + writer.emit(")") + } + writer.emit(SEMICOLON) + } +} diff --git a/src/main/kotlin/net/theevilreaper/dartpoet/function/typedef/TypeDefBuilder.kt b/src/main/kotlin/net/theevilreaper/dartpoet/function/typedef/TypeDefBuilder.kt new file mode 100644 index 00000000..ba75a953 --- /dev/null +++ b/src/main/kotlin/net/theevilreaper/dartpoet/function/typedef/TypeDefBuilder.kt @@ -0,0 +1,104 @@ +package net.theevilreaper.dartpoet.function.typedef + +import net.theevilreaper.dartpoet.parameter.ParameterSpec +import net.theevilreaper.dartpoet.type.ClassName +import net.theevilreaper.dartpoet.type.TypeName +import net.theevilreaper.dartpoet.type.asTypeName +import net.theevilreaper.dartpoet.util.EMPTY_STRING +import kotlin.reflect.KClass + +/** + * The builder is used to create a type definition with a specific name and optional type cast. + * After the construction the builder maps the data into a [TypeDefSpec] object. + * + * @property typeDefName the name of the type definition. + * @property typeCast optional type cast for the type definition. + */ +class TypeDefBuilder internal constructor( + val typeDefName: String, + val typeCast: TypeName? = null +) { + /** + * The name of the type definition. + */ + var name: String? = null + + /** + * The return type of the type definition. + */ + var returnType: TypeName? = null + + /** + * List of parameters associated with the type definition. + */ + val parameters: MutableList = mutableListOf() + + /** + * Sets the name of the type definition. + * + * @param name the name of the type definition. + * @return the current instance of [TypeDefBuilder]. + */ + fun name(name: String) = apply { + this.name = name + } + + /** + * Adds a parameter to the list of parameters. + * + * @param parameterSpec the parameter specification. + * @return the current instance of [TypeDefBuilder]. + */ + fun parameter(parameterSpec: ParameterSpec) = apply { + this.parameters += parameterSpec + } + + /** + * Adds multiple parameters to the list of parameters. + * + * @param parameterSpecs the parameter specifications. + * @return the current instance of [TypeDefBuilder]. + */ + fun parameters(vararg parameterSpecs: ParameterSpec) = apply { + this.parameters += parameterSpecs + } + + /** + * Sets the return type of the type definition. + * + * @param typeName the return type as a [TypeName]. + * @return the current instance of [TypeDefBuilder]. + */ + fun returns(typeName: TypeName) = apply { + this.returnType = typeName + } + + /** + * Sets the return type of the type definition. + * + * @param typeName the return type as a [ClassName]. + * @return the current instance of [TypeDefBuilder]. + */ + fun returns(typeName: ClassName) = apply { + this.returnType = typeName + } + + /** + * Sets the return type of the type definition using a [KClass]. + * + * @param typeName the return type as a [KClass]. + * @return the current instance of [TypeDefBuilder]. + */ + fun returns(typeName: KClass<*>) = apply { + this.returnType = typeName.asTypeName() + } + + /** + * Builds and returns an instance of [TypeDefSpec] based on the configuration. + * + * @return an instance of [TypeDefSpec]. + */ + fun build(): TypeDefSpec { + return TypeDefSpec(this) + } +} diff --git a/src/main/kotlin/net/theevilreaper/dartpoet/function/typedef/TypeDefSpec.kt b/src/main/kotlin/net/theevilreaper/dartpoet/function/typedef/TypeDefSpec.kt new file mode 100644 index 00000000..d4c1eb68 --- /dev/null +++ b/src/main/kotlin/net/theevilreaper/dartpoet/function/typedef/TypeDefSpec.kt @@ -0,0 +1,111 @@ +package net.theevilreaper.dartpoet.function.typedef + +import net.theevilreaper.dartpoet.code.CodeWriter +import net.theevilreaper.dartpoet.code.buildCodeString +import net.theevilreaper.dartpoet.code.writer.FunctionWriter +import net.theevilreaper.dartpoet.code.writer.TypeDefWriter +import net.theevilreaper.dartpoet.type.ClassName +import net.theevilreaper.dartpoet.type.TypeName +import net.theevilreaper.dartpoet.type.asTypeName +import net.theevilreaper.dartpoet.util.toImmutableList +import kotlin.reflect.KClass + +/** + * The class models a typedef from dart into a structure which can be used to generate and organize such methods. + * For more details visit the documentation from dart + * @see Dart Typedefs. + */ +class TypeDefSpec( + val builder: TypeDefBuilder +) { + internal val typeDefName = builder.typeDefName + internal val name = builder.name + internal val typeCast = builder.typeCast + internal val returnType = builder.returnType ?: Void::class.asTypeName() + internal val parameters = builder.parameters.toImmutableList() + internal val hasParameters = parameters.isNotEmpty() + + /** + * Performs some checks to avoid invalid data. + */ + init { + require(typeDefName.trim().isNotEmpty()) { "The name of a typedef can't be empty" } + if (name != null) { + require(name.trim().isNotEmpty()) { "The function name of a typedef can't be empty" } + } + } + + /** + * Calls a [FunctionWriter] to append the content from a spec object to a [CodeWriter]. + * @param codeWriter the writer instance + */ + internal fun write(codeWriter: CodeWriter) { + TypeDefWriter().write(this, codeWriter) + } + + /** + * Creates a textual representation from the spec object. + * @return the spec object as string + */ + override fun toString() = buildCodeString { write(this) } + + /** + * Converts a given instance of a [TypeDefSpec] into a [TypeDefBuilder]. + * This is useful if you want to modify an existing spec object. + * @return the created builder + */ + fun toBuilder(): TypeDefBuilder { + return builder + } + + /** + * The companion object contains some static methods to create a new instance of a [TypeDefSpec]. + * + */ + companion object { + + /** + * Static method to create a new instance from the [TypeDefBuilder]. + * @param typeDefName the name of the typedef + * @return the created instance + */ + @JvmStatic + fun builder(typeDefName: String): TypeDefBuilder = TypeDefBuilder(typeDefName) + + /** + * Static method to create a new instance from the [TypeDefBuilder]. + * @param typeDefName the name of the typedef + * @param typeCast the type cast for the typedef as [TypeName] + * @return the created instance + */ + @JvmStatic + fun builder(typeDefName: String, typeCast: TypeName): TypeDefBuilder = TypeDefBuilder(typeDefName, typeCast) + + /** + * Static method to create a new instance from the [TypeDefBuilder]. + * @param typeDefName the name of the typedef + * @param typeCast the type cast for the typedef as [Class] + * @return the created instance + */ + @JvmStatic + fun builder(typeDefName: String, typeCast: ClassName): TypeDefBuilder = TypeDefBuilder(typeDefName, typeCast) + + /** + * Static method to create a new instance from the [TypeDefBuilder]. + * @param typeDefName the name of the typedef + * @param typeCast the type cast for the typedef as [Class] + * @return the created instance + */ + @JvmStatic + fun builder(typeDefName: String, typeCast: Class<*>): TypeDefBuilder = TypeDefBuilder(typeDefName, typeCast.asTypeName()) + + /** + * Static method to create a new instance from the [TypeDefBuilder]. + * @param typeDefName the name of the typedef + * @param typeCast the type cast for the typedef as [KClass] + * @return the created instance + */ + @JvmStatic + fun builder(typeDefName: String, typeCast: KClass<*>): TypeDefBuilder = TypeDefBuilder(typeDefName, typeCast.asTypeName()) + } +} \ No newline at end of file From 44b4970ea0c9e8f0dc08f4f0d5d1a9f0e82f21c2 Mon Sep 17 00:00:00 2001 From: theEvilReaper Date: Wed, 10 Jan 2024 12:20:54 +0100 Subject: [PATCH 04/15] Integrate the updated typedef structure into other spec objects, writers --- .../net/theevilreaper/dartpoet/DartFile.kt | 4 ++++ .../theevilreaper/dartpoet/DartFileBuilder.kt | 20 +++++++++++++++++++ .../dartpoet/clazz/ClassBuilder.kt | 10 ++++++++++ .../theevilreaper/dartpoet/clazz/ClassSpec.kt | 4 ++-- .../dartpoet/code/writer/ClassWriter.kt | 16 ++++++--------- .../dartpoet/code/writer/DartFileWriter.kt | 4 ++++ 6 files changed, 46 insertions(+), 12 deletions(-) diff --git a/src/main/kotlin/net/theevilreaper/dartpoet/DartFile.kt b/src/main/kotlin/net/theevilreaper/dartpoet/DartFile.kt index c2da0b44..243db139 100644 --- a/src/main/kotlin/net/theevilreaper/dartpoet/DartFile.kt +++ b/src/main/kotlin/net/theevilreaper/dartpoet/DartFile.kt @@ -38,6 +38,10 @@ class DartFile internal constructor( internal val libImport = DirectiveOrdering.sortDirectives(LibraryDirective::class, directives) internal val exportDirectives = DirectiveOrdering.sortDirectives(ExportDirective::class, directives) internal val relativeImports = DirectiveOrdering.sortDirectives(RelativeDirective::class, directives) + + internal val typeDefs = builder.typeDefs.toImmutableList() + internal val hasTypeDefs = typeDefs.isNotEmpty() + init { check(name.trim().isNotEmpty()) { "The name of a class can't be empty (ONLY SPACES ARE NOT ALLOWED" } if (libImport.isNotEmpty()) { diff --git a/src/main/kotlin/net/theevilreaper/dartpoet/DartFileBuilder.kt b/src/main/kotlin/net/theevilreaper/dartpoet/DartFileBuilder.kt index 315ece1a..59b616c9 100644 --- a/src/main/kotlin/net/theevilreaper/dartpoet/DartFileBuilder.kt +++ b/src/main/kotlin/net/theevilreaper/dartpoet/DartFileBuilder.kt @@ -6,6 +6,7 @@ import net.theevilreaper.dartpoet.clazz.ClassSpec import net.theevilreaper.dartpoet.code.CodeBlock import net.theevilreaper.dartpoet.extension.ExtensionSpec import net.theevilreaper.dartpoet.directive.Directive +import net.theevilreaper.dartpoet.function.typedef.TypeDefSpec import net.theevilreaper.dartpoet.property.consts.ConstantPropertySpec import net.theevilreaper.dartpoet.property.PropertySpec import net.theevilreaper.dartpoet.util.DEFAULT_INDENT @@ -20,6 +21,7 @@ class DartFileBuilder( internal val annotations: MutableList = mutableListOf() internal val extensionStack: MutableList = mutableListOf() internal val constants: MutableSet = mutableSetOf() + internal val typeDefs: MutableList = mutableListOf() internal var indent = DEFAULT_INDENT /** @@ -71,6 +73,24 @@ class DartFileBuilder( this.extensionStack += extensions } + /** + * Add a type definition to the file builder. + * @param typeDef the type definition to add + * @return the current instance of [DartFileBuilder] + */ + fun typeDef(typeDef: TypeDefSpec) = apply { + this.typeDefs += typeDef + } + + /** + * Add an array of type definitions to the file builder. + * @param typeDef the type definitions to add + * @return the current instance of [DartFileBuilder] + */ + fun typeDef(vararg typeDef: TypeDefSpec) = apply { + this.typeDefs += typeDef + } + fun type(dartFileSpec: ClassSpec) = apply { this.specTypes += dartFileSpec } diff --git a/src/main/kotlin/net/theevilreaper/dartpoet/clazz/ClassBuilder.kt b/src/main/kotlin/net/theevilreaper/dartpoet/clazz/ClassBuilder.kt index 528c1828..cb7f7466 100644 --- a/src/main/kotlin/net/theevilreaper/dartpoet/clazz/ClassBuilder.kt +++ b/src/main/kotlin/net/theevilreaper/dartpoet/clazz/ClassBuilder.kt @@ -8,6 +8,7 @@ import net.theevilreaper.dartpoet.function.FunctionSpec import net.theevilreaper.dartpoet.meta.SpecData import net.theevilreaper.dartpoet.meta.SpecMethods import net.theevilreaper.dartpoet.function.constructor.ConstructorSpec +import net.theevilreaper.dartpoet.function.typedef.TypeDefSpec import net.theevilreaper.dartpoet.property.PropertySpec import net.theevilreaper.dartpoet.property.consts.ConstantPropertySpec import net.theevilreaper.dartpoet.type.TypeName @@ -32,6 +33,7 @@ class ClassBuilder internal constructor( internal val functionStack: MutableList = mutableListOf() internal val enumPropertyStack: MutableList = mutableListOf() internal val constantStack: MutableSet = mutableSetOf() + internal val typedefs: MutableList = mutableListOf() internal var superClass: TypeName? = null internal var inheritKeyWord: InheritKeyword? = null internal var endWithNewLine = false @@ -53,6 +55,14 @@ class ClassBuilder internal constructor( this.constantStack += constants } + fun typedef(typeDefSpec: TypeDefSpec) = apply { + this.typedefs += typeDefSpec + } + + fun typedef(vararg typeDefSpec: TypeDefSpec) = apply { + this.typedefs += typeDefSpec + } + /** * Add a [EnumPropertySpec] to the spec. * @param enumPropertySpec the property to add diff --git a/src/main/kotlin/net/theevilreaper/dartpoet/clazz/ClassSpec.kt b/src/main/kotlin/net/theevilreaper/dartpoet/clazz/ClassSpec.kt index 4094c39b..251eb022 100644 --- a/src/main/kotlin/net/theevilreaper/dartpoet/clazz/ClassSpec.kt +++ b/src/main/kotlin/net/theevilreaper/dartpoet/clazz/ClassSpec.kt @@ -31,10 +31,10 @@ class ClassSpec internal constructor( internal val superClass = builder.superClass internal val inheritKeyWord = builder.inheritKeyWord internal val classModifiers = modifiers.filter { it != WITH }.toImmutableSet() - internal val functions = builder.functionStack.filter { !it.isTypeDef }.toImmutableSet() + internal val typeDefs = builder.typedefs.toImmutableList() + internal val functions = builder.functionStack.toImmutableSet() internal val properties = builder.propertyStack.toImmutableSet() internal val constructors = builder.constructorStack.toImmutableSet() - internal val typeDefStack = builder.functionStack.filter { it.isTypeDef }.toImmutableSet() internal val enumPropertyStack = builder.enumPropertyStack.toImmutableList() internal var constantStack = builder.constantStack.toImmutableSet() diff --git a/src/main/kotlin/net/theevilreaper/dartpoet/code/writer/ClassWriter.kt b/src/main/kotlin/net/theevilreaper/dartpoet/code/writer/ClassWriter.kt index e450789d..0e821596 100644 --- a/src/main/kotlin/net/theevilreaper/dartpoet/code/writer/ClassWriter.kt +++ b/src/main/kotlin/net/theevilreaper/dartpoet/code/writer/ClassWriter.kt @@ -23,15 +23,13 @@ internal class ClassWriter : Writeable { //TODO: Improve new lines after each generated code part block override fun write(spec: ClassSpec, writer: CodeWriter) { + if (spec.typeDefs.isNotEmpty()) { + spec.typeDefs.emitTypeDefs(writer) + } if (spec.isAnonymous) { writeAnonymousClass(spec, writer) return } - spec.typeDefStack.emitFunctions(writer) - - if (spec.typeDefStack.isNotEmpty()) { - writer.emit(NEW_LINE) - } spec.annotations.emitAnnotations(writer, inLineAnnotations = false) writeClassHeader(spec, writer) @@ -100,13 +98,11 @@ internal class ClassWriter : Writeable { } private fun writeAnonymousClass(spec: ClassSpec, writer: CodeWriter) { - spec.typeDefStack.emitFunctions(writer) { + /*spec.typeDefStack.emitFunctions(writer) { it.write(writer) - } + }*/ - spec.functions.emitFunctions(writer) { - it.write(writer) - } + spec.functions.emitFunctions(writer) if (spec.endsWithNewLine) { writer.emit(NEW_LINE) diff --git a/src/main/kotlin/net/theevilreaper/dartpoet/code/writer/DartFileWriter.kt b/src/main/kotlin/net/theevilreaper/dartpoet/code/writer/DartFileWriter.kt index 9c9aa13d..e73d6211 100644 --- a/src/main/kotlin/net/theevilreaper/dartpoet/code/writer/DartFileWriter.kt +++ b/src/main/kotlin/net/theevilreaper/dartpoet/code/writer/DartFileWriter.kt @@ -25,6 +25,10 @@ internal class DartFileWriter : Writeable, DocumentationAppender { writer.emit(NEW_LINE) } + if (spec.hasTypeDefs) { + spec.typeDefs.emitTypeDefs(writer) + } + if (spec.types.isNotEmpty()) { spec.types.forEach { classWriter.write(it, writer) From 54806da27172d3884a892142a11219a9e2c05d9c Mon Sep 17 00:00:00 2001 From: theEvilReaper Date: Wed, 10 Jan 2024 12:21:17 +0100 Subject: [PATCH 05/15] Add test classes for the typedef structure --- .../dartpoet/code/writer/TypeDefWriterTest.kt | 49 +++++++++++++++++ .../function/typedef/TypeDefSpecTest.kt | 53 +++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 src/test/kotlin/net/theevilreaper/dartpoet/code/writer/TypeDefWriterTest.kt create mode 100644 src/test/kotlin/net/theevilreaper/dartpoet/function/typedef/TypeDefSpecTest.kt diff --git a/src/test/kotlin/net/theevilreaper/dartpoet/code/writer/TypeDefWriterTest.kt b/src/test/kotlin/net/theevilreaper/dartpoet/code/writer/TypeDefWriterTest.kt new file mode 100644 index 00000000..11973911 --- /dev/null +++ b/src/test/kotlin/net/theevilreaper/dartpoet/code/writer/TypeDefWriterTest.kt @@ -0,0 +1,49 @@ +package net.theevilreaper.dartpoet.code.writer + +import com.google.common.truth.Truth +import net.theevilreaper.dartpoet.function.typedef.TypeDefSpec +import net.theevilreaper.dartpoet.parameter.ParameterSpec +import net.theevilreaper.dartpoet.type.ClassName +import net.theevilreaper.dartpoet.type.DYNAMIC +import net.theevilreaper.dartpoet.type.ParameterizedTypeName.Companion.parameterizedBy +import net.theevilreaper.dartpoet.type.asTypeName +import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource +import java.util.stream.Stream + +class TypeDefWriterTest { + + companion object { + + private val genericClassName = ClassName("E") + + @JvmStatic + private fun typeDefs(): Stream = Stream.of( + Arguments.of( + TypeDefSpec.builder("ValueUpdate", genericClassName) + .parameter( + ParameterSpec.builder("value", genericClassName) + .nullable(true) + .build() + ) + .name("Function") + .build(), + "typedef ValueUpdate = void Function(E? value);" + ), + Arguments.of( + TypeDefSpec.builder("json") + .returns(Map::class.parameterizedBy(String::class.asTypeName(), DYNAMIC)) + .build(), + "typedef json = Map;" + ) + ) + } + + @ParameterizedTest + @MethodSource("typeDefs") + fun `test typedef write`(typeDef: TypeDefSpec, expected: String) { + Truth.assertThat(typeDef.toString()).isEqualTo(expected) + } +} diff --git a/src/test/kotlin/net/theevilreaper/dartpoet/function/typedef/TypeDefSpecTest.kt b/src/test/kotlin/net/theevilreaper/dartpoet/function/typedef/TypeDefSpecTest.kt new file mode 100644 index 00000000..74483b32 --- /dev/null +++ b/src/test/kotlin/net/theevilreaper/dartpoet/function/typedef/TypeDefSpecTest.kt @@ -0,0 +1,53 @@ +package net.theevilreaper.dartpoet.function.typedef + +import net.theevilreaper.dartpoet.parameter.ParameterSpec +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.MethodSource +import java.util.stream.Stream + +class TypeDefSpecTest { + + companion object { + + @JvmStatic + private fun invalidTypeDefs(): Stream = Stream.of( + Arguments.of( + IllegalArgumentException::class.java, + { TypeDefSpec.builder("").build() }, + "The name of a typedef can't be empty" + ), + Arguments.of( + IllegalArgumentException::class.java, + { TypeDefSpec.builder("Test", Int::class) + .name("") + .returns(String::class).build() + }, + "The function name of a typedef can't be empty" + ) + ) + } + + @ParameterizedTest + @MethodSource("invalidTypeDefs") + fun `test invalid typedef creation`(exception: Class, function: () -> Unit, message: String) { + val exceptionMessage = assertThrows(exception, function, message).message + assertEquals(message, exceptionMessage) + } + + @Test + fun `test to builder method`() { + val typeSpec = TypeDefSpec.builder("Test", Int::class) + .name("Function") + .returns(String::class).build() + assertNotEquals(Void::class.java, typeSpec.returnType) + + val newBuilder = typeSpec.toBuilder() + newBuilder.parameter(ParameterSpec.builder("test", String::class).build()) + + val newTypeSpec = newBuilder.build() + assertNotEquals(typeSpec.parameters, newTypeSpec.parameters) + } +} \ No newline at end of file From 3a66c73d4ab7b1d7d4e7053c508e7c635b8fa46c Mon Sep 17 00:00:00 2001 From: theEvilReaper Date: Wed, 10 Jan 2024 12:21:39 +0100 Subject: [PATCH 06/15] Update given tests to support typedef creation --- .../net/theevilreaper/dartpoet/DartFileTest.kt | 6 +++--- .../dartpoet/code/writer/FunctionWriterTest.kt | 14 -------------- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/test/kotlin/net/theevilreaper/dartpoet/DartFileTest.kt b/src/test/kotlin/net/theevilreaper/dartpoet/DartFileTest.kt index b37abbe1..9a76aafa 100644 --- a/src/test/kotlin/net/theevilreaper/dartpoet/DartFileTest.kt +++ b/src/test/kotlin/net/theevilreaper/dartpoet/DartFileTest.kt @@ -11,6 +11,7 @@ import net.theevilreaper.dartpoet.directive.DartDirective import net.theevilreaper.dartpoet.directive.CastType import net.theevilreaper.dartpoet.directive.LibraryDirective import net.theevilreaper.dartpoet.directive.PartDirective +import net.theevilreaper.dartpoet.function.typedef.TypeDefSpec import net.theevilreaper.dartpoet.property.consts.ConstantPropertySpec import net.theevilreaper.dartpoet.parameter.ParameterSpec import net.theevilreaper.dartpoet.property.PropertySpec @@ -124,9 +125,8 @@ class DartFileTest { .type( ClassSpec.anonymousClassBuilder() .endWithNewLine(true) - .function( - FunctionSpec.builder("JsonMap") - .typedef(true) + .typedef( + TypeDefSpec.builder("JsonMap") .returns(Map::class.parameterizedBy(String::class.asTypeName(), DYNAMIC)) .build() diff --git a/src/test/kotlin/net/theevilreaper/dartpoet/code/writer/FunctionWriterTest.kt b/src/test/kotlin/net/theevilreaper/dartpoet/code/writer/FunctionWriterTest.kt index 137f1200..1ef9c5c8 100644 --- a/src/test/kotlin/net/theevilreaper/dartpoet/code/writer/FunctionWriterTest.kt +++ b/src/test/kotlin/net/theevilreaper/dartpoet/code/writer/FunctionWriterTest.kt @@ -154,20 +154,6 @@ class FunctionWriterTest { ) } - @Test - fun `test typedef write`() { - val function = FunctionSpec.builder("ValueUpdate") - .typedef(true) - .parameter( - ParameterSpec.builder("value", ClassName("E")) - .nullable(true) - .build() - ) - .returns(ClassName("void Function")) - .build() - assertThat(function.toString()).isEqualTo("typedef ValueUpdate = void Function(E? value);") - } - @Test fun `test other getter variant write`() { val function = FunctionSpec.builder("value") From 35ef1a00289bc3a4393fbdc1a864333c8176ecfe Mon Sep 17 00:00:00 2001 From: theEvilReaper Date: Wed, 10 Jan 2024 13:36:15 +0100 Subject: [PATCH 07/15] Remove typedef as valid function modifier --- src/main/kotlin/net/theevilreaper/dartpoet/util/Constants.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/kotlin/net/theevilreaper/dartpoet/util/Constants.kt b/src/main/kotlin/net/theevilreaper/dartpoet/util/Constants.kt index dd78cd61..641c885b 100644 --- a/src/main/kotlin/net/theevilreaper/dartpoet/util/Constants.kt +++ b/src/main/kotlin/net/theevilreaper/dartpoet/util/Constants.kt @@ -26,8 +26,7 @@ internal const val CURLY_CLOSE = '}' internal const val ROUND_OPEN = "(" internal const val ROUND_CLOSE = ")" -internal val ALLOWED_FUNCTION_MODIFIERS = - setOf(DartModifier.PUBLIC, DartModifier.PRIVATE, DartModifier.STATIC, DartModifier.TYPEDEF) +internal val ALLOWED_FUNCTION_MODIFIERS = setOf(DartModifier.PUBLIC, DartModifier.PRIVATE, DartModifier.STATIC) internal val ALLOWED_PROPERTY_MODIFIERS = setOf(DartModifier.PRIVATE, DartModifier.FINAL, DartModifier.LATE, DartModifier.STATIC, DartModifier.CONST) internal val ALLOWED_CLASS_CONST_MODIFIERS = setOf(DartModifier.CONST) From 19cabb7de96131710867ddcc2a4ed719b8cf4e3e Mon Sep 17 00:00:00 2001 From: theEvilReaper Date: Wed, 10 Jan 2024 13:36:32 +0100 Subject: [PATCH 08/15] Remove empty line --- .../kotlin/net/theevilreaper/dartpoet/function/FunctionSpec.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/kotlin/net/theevilreaper/dartpoet/function/FunctionSpec.kt b/src/main/kotlin/net/theevilreaper/dartpoet/function/FunctionSpec.kt index 3bac2f1e..223c639c 100644 --- a/src/main/kotlin/net/theevilreaper/dartpoet/function/FunctionSpec.kt +++ b/src/main/kotlin/net/theevilreaper/dartpoet/function/FunctionSpec.kt @@ -23,7 +23,6 @@ import net.theevilreaper.dartpoet.util.toImmutableSet class FunctionSpec( builder: FunctionBuilder ) { - internal val name = builder.name internal val returnType: TypeName? = builder.returnType internal val body: CodeBlock = builder.body.build() @@ -33,7 +32,7 @@ class FunctionSpec( internal var modifiers: Set = builder.specData.modifiers.also { hasAllowedModifiers(it, ALLOWED_FUNCTION_MODIFIERS, "function") }.filter { it != DartModifier.PRIVATE && it != DartModifier.PUBLIC }.toImmutableSet() - internal val isPrivate = builder.specData.modifiers.contains(DartModifier.PRIVATE) + internal val isPrivate = builder.specData.modifiers.remove(DartModifier.PRIVATE) internal val typeCast = builder.typeCast internal val asSetter = builder.setter internal val isGetter = builder.getter From aa92d876b500ad0a5b7b5ac2c77b3f25c476019d Mon Sep 17 00:00:00 2001 From: theEvilReaper Date: Wed, 10 Jan 2024 15:42:02 +0100 Subject: [PATCH 09/15] Remove unused code --- .../net/theevilreaper/dartpoet/code/writer/ClassWriter.kt | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/main/kotlin/net/theevilreaper/dartpoet/code/writer/ClassWriter.kt b/src/main/kotlin/net/theevilreaper/dartpoet/code/writer/ClassWriter.kt index 0e821596..81dac761 100644 --- a/src/main/kotlin/net/theevilreaper/dartpoet/code/writer/ClassWriter.kt +++ b/src/main/kotlin/net/theevilreaper/dartpoet/code/writer/ClassWriter.kt @@ -23,9 +23,6 @@ internal class ClassWriter : Writeable { //TODO: Improve new lines after each generated code part block override fun write(spec: ClassSpec, writer: CodeWriter) { - if (spec.typeDefs.isNotEmpty()) { - spec.typeDefs.emitTypeDefs(writer) - } if (spec.isAnonymous) { writeAnonymousClass(spec, writer) return @@ -98,10 +95,7 @@ internal class ClassWriter : Writeable { } private fun writeAnonymousClass(spec: ClassSpec, writer: CodeWriter) { - /*spec.typeDefStack.emitFunctions(writer) { - it.write(writer) - }*/ - + spec.typeDefs.emitTypeDefs(writer) spec.functions.emitFunctions(writer) if (spec.endsWithNewLine) { From 6f6e90139406b5c635ea9b7d987be2e487a5ab62 Mon Sep 17 00:00:00 2001 From: theEvilReaper Date: Wed, 10 Jan 2024 15:43:25 +0100 Subject: [PATCH 10/15] Improve code layout --- .../theevilreaper/dartpoet/function/typedef/TypeDefSpec.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/net/theevilreaper/dartpoet/function/typedef/TypeDefSpec.kt b/src/main/kotlin/net/theevilreaper/dartpoet/function/typedef/TypeDefSpec.kt index d4c1eb68..c2817328 100644 --- a/src/main/kotlin/net/theevilreaper/dartpoet/function/typedef/TypeDefSpec.kt +++ b/src/main/kotlin/net/theevilreaper/dartpoet/function/typedef/TypeDefSpec.kt @@ -97,7 +97,8 @@ class TypeDefSpec( * @return the created instance */ @JvmStatic - fun builder(typeDefName: String, typeCast: Class<*>): TypeDefBuilder = TypeDefBuilder(typeDefName, typeCast.asTypeName()) + fun builder(typeDefName: String, typeCast: Class<*>): TypeDefBuilder = + TypeDefBuilder(typeDefName, typeCast.asTypeName()) /** * Static method to create a new instance from the [TypeDefBuilder]. @@ -106,6 +107,7 @@ class TypeDefSpec( * @return the created instance */ @JvmStatic - fun builder(typeDefName: String, typeCast: KClass<*>): TypeDefBuilder = TypeDefBuilder(typeDefName, typeCast.asTypeName()) + fun builder(typeDefName: String, typeCast: KClass<*>): TypeDefBuilder = + TypeDefBuilder(typeDefName, typeCast.asTypeName()) } } \ No newline at end of file From 0d6855585d527b4e242d0e18720a1cc429faea13 Mon Sep 17 00:00:00 2001 From: theEvilReaper Date: Wed, 10 Jan 2024 15:43:39 +0100 Subject: [PATCH 11/15] Remove out commented code --- .../kotlin/net/theevilreaper/dartpoet/function/FunctionSpec.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/kotlin/net/theevilreaper/dartpoet/function/FunctionSpec.kt b/src/main/kotlin/net/theevilreaper/dartpoet/function/FunctionSpec.kt index 223c639c..c75bd59f 100644 --- a/src/main/kotlin/net/theevilreaper/dartpoet/function/FunctionSpec.kt +++ b/src/main/kotlin/net/theevilreaper/dartpoet/function/FunctionSpec.kt @@ -47,7 +47,6 @@ class FunctionSpec( } init { - //check(!isTypeDef && annotation.isNotEmpty()) { "A typedef can't have annotations" } require(name.trim().isNotEmpty()) { "The name of a function can't be empty" } require(body.isEmpty() || !modifiers.contains(DartModifier.ABSTRACT)) { "An abstract method can't have a body" } From a540d5f710f62bb5c209e53512728117c7e7ba00 Mon Sep 17 00:00:00 2001 From: theEvilReaper Date: Wed, 10 Jan 2024 17:13:52 +0100 Subject: [PATCH 12/15] Improve new line write --- .../net/theevilreaper/dartpoet/code/CodeWriterExtension.kt | 1 + src/test/kotlin/net/theevilreaper/dartpoet/DartFileTest.kt | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/net/theevilreaper/dartpoet/code/CodeWriterExtension.kt b/src/main/kotlin/net/theevilreaper/dartpoet/code/CodeWriterExtension.kt index a964dc42..2cc70a8e 100644 --- a/src/main/kotlin/net/theevilreaper/dartpoet/code/CodeWriterExtension.kt +++ b/src/main/kotlin/net/theevilreaper/dartpoet/code/CodeWriterExtension.kt @@ -211,6 +211,7 @@ fun List.emitTypeDefs( } emitBlock(typeDefSpec) } + emit(NEW_LINE) } fun Set.emitProperties( diff --git a/src/test/kotlin/net/theevilreaper/dartpoet/DartFileTest.kt b/src/test/kotlin/net/theevilreaper/dartpoet/DartFileTest.kt index 9a76aafa..1aab39ea 100644 --- a/src/test/kotlin/net/theevilreaper/dartpoet/DartFileTest.kt +++ b/src/test/kotlin/net/theevilreaper/dartpoet/DartFileTest.kt @@ -124,7 +124,6 @@ class DartFileTest { val libClass = DartFile.builder("testLib") .type( ClassSpec.anonymousClassBuilder() - .endWithNewLine(true) .typedef( TypeDefSpec.builder("JsonMap") .returns(Map::class.parameterizedBy(String::class.asTypeName(), DYNAMIC)) @@ -429,4 +428,4 @@ class DartFileTest { """.trimIndent() ) } -} +} \ No newline at end of file From 7e07bcd24ede36c40383feb3d97b35b9d8080ea7 Mon Sep 17 00:00:00 2001 From: theEvilReaper Date: Wed, 10 Jan 2024 20:06:01 +0100 Subject: [PATCH 13/15] Add support for multiple cast arguments --- .../dartpoet/code/writer/TypeDefWriter.kt | 5 +++-- .../function/typedef/TypeDefBuilder.kt | 5 ++--- .../dartpoet/function/typedef/TypeDefSpec.kt | 22 ++++++++++--------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/main/kotlin/net/theevilreaper/dartpoet/code/writer/TypeDefWriter.kt b/src/main/kotlin/net/theevilreaper/dartpoet/code/writer/TypeDefWriter.kt index b748f1f4..4ea76f0c 100644 --- a/src/main/kotlin/net/theevilreaper/dartpoet/code/writer/TypeDefWriter.kt +++ b/src/main/kotlin/net/theevilreaper/dartpoet/code/writer/TypeDefWriter.kt @@ -10,8 +10,9 @@ import net.theevilreaper.dartpoet.util.SEMICOLON class TypeDefWriter : Writeable { override fun write(spec: TypeDefSpec, writer: CodeWriter) { writer.emit("${DartModifier.TYPEDEF.identifier}·${spec.typeDefName}") - if (spec.typeCast != null) { - writer.emitCode("<%T>", spec.typeCast) + if (spec.typeCasts.isNotEmpty()) { + val typesAsString = spec.typeCasts.joinToString(separator = ",·") { it.toString() } + writer.emitCode("<%L>", typesAsString) } writer.emit("·=·") writer.emitCode("%T", spec.returnType) diff --git a/src/main/kotlin/net/theevilreaper/dartpoet/function/typedef/TypeDefBuilder.kt b/src/main/kotlin/net/theevilreaper/dartpoet/function/typedef/TypeDefBuilder.kt index ba75a953..1ef14fda 100644 --- a/src/main/kotlin/net/theevilreaper/dartpoet/function/typedef/TypeDefBuilder.kt +++ b/src/main/kotlin/net/theevilreaper/dartpoet/function/typedef/TypeDefBuilder.kt @@ -4,7 +4,6 @@ import net.theevilreaper.dartpoet.parameter.ParameterSpec import net.theevilreaper.dartpoet.type.ClassName import net.theevilreaper.dartpoet.type.TypeName import net.theevilreaper.dartpoet.type.asTypeName -import net.theevilreaper.dartpoet.util.EMPTY_STRING import kotlin.reflect.KClass /** @@ -12,11 +11,11 @@ import kotlin.reflect.KClass * After the construction the builder maps the data into a [TypeDefSpec] object. * * @property typeDefName the name of the type definition. - * @property typeCast optional type cast for the type definition. + * @property typeCasts optional array of type-cast for the type definition. */ class TypeDefBuilder internal constructor( val typeDefName: String, - val typeCast: TypeName? = null + vararg val typeCasts: TypeName? = emptyArray() ) { /** * The name of the type definition. diff --git a/src/main/kotlin/net/theevilreaper/dartpoet/function/typedef/TypeDefSpec.kt b/src/main/kotlin/net/theevilreaper/dartpoet/function/typedef/TypeDefSpec.kt index c2817328..880f4d84 100644 --- a/src/main/kotlin/net/theevilreaper/dartpoet/function/typedef/TypeDefSpec.kt +++ b/src/main/kotlin/net/theevilreaper/dartpoet/function/typedef/TypeDefSpec.kt @@ -20,7 +20,7 @@ class TypeDefSpec( ) { internal val typeDefName = builder.typeDefName internal val name = builder.name - internal val typeCast = builder.typeCast + internal val typeCasts = builder.typeCasts internal val returnType = builder.returnType ?: Void::class.asTypeName() internal val parameters = builder.parameters.toImmutableList() internal val hasParameters = parameters.isNotEmpty() @@ -75,11 +75,12 @@ class TypeDefSpec( /** * Static method to create a new instance from the [TypeDefBuilder]. * @param typeDefName the name of the typedef - * @param typeCast the type cast for the typedef as [TypeName] + * @param typeCasts the type cast for the typedef as [TypeName] * @return the created instance */ @JvmStatic - fun builder(typeDefName: String, typeCast: TypeName): TypeDefBuilder = TypeDefBuilder(typeDefName, typeCast) + fun builder(typeDefName: String, vararg typeCasts: TypeName): TypeDefBuilder = + TypeDefBuilder(typeDefName, *typeCasts) /** * Static method to create a new instance from the [TypeDefBuilder]. @@ -88,26 +89,27 @@ class TypeDefSpec( * @return the created instance */ @JvmStatic - fun builder(typeDefName: String, typeCast: ClassName): TypeDefBuilder = TypeDefBuilder(typeDefName, typeCast) + fun builder(typeDefName: String, vararg typeCasts: ClassName): TypeDefBuilder = + TypeDefBuilder(typeDefName, *typeCasts) /** * Static method to create a new instance from the [TypeDefBuilder]. * @param typeDefName the name of the typedef - * @param typeCast the type cast for the typedef as [Class] + * @param typeCasts the type cast for the typedef as [Class] * @return the created instance */ @JvmStatic - fun builder(typeDefName: String, typeCast: Class<*>): TypeDefBuilder = - TypeDefBuilder(typeDefName, typeCast.asTypeName()) + fun builder(typeDefName: String, vararg typeCasts: Class<*>): TypeDefBuilder = + TypeDefBuilder(typeDefName, *typeCasts.map { it.asTypeName() }.toTypedArray()) /** * Static method to create a new instance from the [TypeDefBuilder]. * @param typeDefName the name of the typedef - * @param typeCast the type cast for the typedef as [KClass] + * @param typeCasts the type cast for the typedef as [KClass] * @return the created instance */ @JvmStatic - fun builder(typeDefName: String, typeCast: KClass<*>): TypeDefBuilder = - TypeDefBuilder(typeDefName, typeCast.asTypeName()) + fun builder(typeDefName: String, vararg typeCasts: KClass<*>): TypeDefBuilder = + TypeDefBuilder(typeDefName, *typeCasts.map { it.asTypeName() }.toTypedArray()) } } \ No newline at end of file From 183dd498ffb42d7d250fd838968bd1c7ffc5e78e Mon Sep 17 00:00:00 2001 From: theEvilReaper Date: Wed, 10 Jan 2024 20:11:17 +0100 Subject: [PATCH 14/15] Add test for the multiple cast arguments --- .../dartpoet/code/writer/TypeDefWriterTest.kt | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/test/kotlin/net/theevilreaper/dartpoet/code/writer/TypeDefWriterTest.kt b/src/test/kotlin/net/theevilreaper/dartpoet/code/writer/TypeDefWriterTest.kt index 11973911..16a876cc 100644 --- a/src/test/kotlin/net/theevilreaper/dartpoet/code/writer/TypeDefWriterTest.kt +++ b/src/test/kotlin/net/theevilreaper/dartpoet/code/writer/TypeDefWriterTest.kt @@ -18,6 +18,7 @@ class TypeDefWriterTest { companion object { private val genericClassName = ClassName("E") + private val secondGenericClassName = ClassName("T") @JvmStatic private fun typeDefs(): Stream = Stream.of( @@ -37,6 +38,40 @@ class TypeDefWriterTest { .returns(Map::class.parameterizedBy(String::class.asTypeName(), DYNAMIC)) .build(), "typedef json = Map;" + ), + ) + + @JvmStatic + private fun multipleCastArguments(): Stream = Stream.of( + Arguments.of( + TypeDefSpec.builder( + "DoubleValueUpdate", + genericClassName, secondGenericClassName + ) + .name("Function") + .parameters( + ParameterSpec.builder("first", genericClassName) + .nullable(true) + .build(), + ParameterSpec.builder("second", secondGenericClassName) + .nullable(true) + .build() + ) + .build(), + "typedef DoubleValueUpdate = void Function(E? first, T? second);" + ), + Arguments.of( + TypeDefSpec.builder("Compare", genericClassName, secondGenericClassName) + .returns(Int::class) + .name("Function") + .parameters( + ParameterSpec.builder("a", genericClassName) + .build(), + ParameterSpec.builder("b", genericClassName) + .build() + ) + .build(), + "typedef Compare = int Function(E a, E b);" ) ) } @@ -46,4 +81,10 @@ class TypeDefWriterTest { fun `test typedef write`(typeDef: TypeDefSpec, expected: String) { Truth.assertThat(typeDef.toString()).isEqualTo(expected) } + + @ParameterizedTest + @MethodSource("multipleCastArguments") + fun `test typedef write with multiple casts`(typeDef: TypeDefSpec, expected: String) { + Truth.assertThat(typeDef.toString()).isEqualTo(expected) + } } From 81809a3dad4da01ae8c63ff00d4469169b7bf68e Mon Sep 17 00:00:00 2001 From: theEvilReaper Date: Wed, 10 Jan 2024 20:17:01 +0100 Subject: [PATCH 15/15] Remove unused import --- .../net/theevilreaper/dartpoet/code/writer/TypeDefWriterTest.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/kotlin/net/theevilreaper/dartpoet/code/writer/TypeDefWriterTest.kt b/src/test/kotlin/net/theevilreaper/dartpoet/code/writer/TypeDefWriterTest.kt index 16a876cc..50b78544 100644 --- a/src/test/kotlin/net/theevilreaper/dartpoet/code/writer/TypeDefWriterTest.kt +++ b/src/test/kotlin/net/theevilreaper/dartpoet/code/writer/TypeDefWriterTest.kt @@ -7,7 +7,6 @@ import net.theevilreaper.dartpoet.type.ClassName import net.theevilreaper.dartpoet.type.DYNAMIC import net.theevilreaper.dartpoet.type.ParameterizedTypeName.Companion.parameterizedBy import net.theevilreaper.dartpoet.type.asTypeName -import org.junit.jupiter.api.Test import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.provider.Arguments import org.junit.jupiter.params.provider.MethodSource