From 4b5ee13698bebee73188368d6f2acc0f3907e0f5 Mon Sep 17 00:00:00 2001 From: Jan Galinski Date: Wed, 11 Sep 2024 23:58:43 +0200 Subject: [PATCH] Feature/51 delegate list and map (#53) Introduce opinionated builders for Exception, Delegate-List and Delegate-Map. refactor and simplify --- .../test/kotlin/DelegateStringListITest.kt | 41 +++++++ .../test/kotlin/DelegateStringLongMapITest.kt | 44 +++++++ .../src/test/kotlin/DummyExceptionITest.kt | 52 ++++++++ .../src/test/kotlin/HelloWorldExampleITest.kt | 1 - .../src/main/kotlin/KotlinCodeGeneration.kt | 116 +++++++++++++++--- .../KotlinAnnotationClassSpecBuilder.kt | 55 ++++++--- .../builder/KotlinAnnotationSpecBuilder.kt | 65 +++++++++- .../KotlinAnonymousClassSpecBuilder.kt | 34 ++--- .../kotlin/builder/KotlinClassSpecBuilder.kt | 46 ++++--- .../KotlinCompanionObjectSpecBuilder.kt | 44 +++---- .../KotlinConstructorPropertySpecBuilder.kt | 34 ++--- .../builder/KotlinDataClassSpecBuilder.kt | 40 +++--- .../builder/KotlinEnumClassSpecBuilder.kt | 35 +++--- .../kotlin/builder/KotlinFileSpecBuilder.kt | 46 ++++--- .../kotlin/builder/KotlinFunSpecBuilder.kt | 41 +++++-- .../builder/KotlinInterfaceSpecBuilder.kt | 27 ++-- .../kotlin/builder/KotlinObjectSpecBuilder.kt | 38 +++--- .../builder/KotlinParameterSpecBuilder.kt | 40 ++++-- .../builder/KotlinPropertySpecBuilder.kt | 40 ++++-- .../builder/KotlinTypeAliasSpecBuilder.kt | 24 ++-- .../builder/KotlinValueClassSpecBuilder.kt | 59 ++++++--- .../src/main/kotlin/builder/_types.kt | 8 +- .../DelegateListValueClassSpecBuilder.kt | 85 +++++++++++++ .../extra/DelegateMapValueClassSpecBuilder.kt | 85 +++++++++++++ .../extra/RuntimeExceptionSpecBuilder.kt | 69 ++++++++--- .../main/kotlin/poet/AnnotationSpecBuilder.kt | 15 ++- .../src/main/kotlin/poet/FileSpecBuilder.kt | 1 + .../src/main/kotlin/poet/FunSpecBuilder.kt | 1 + .../main/kotlin/poet/ParameterSpecBuilder.kt | 1 + .../main/kotlin/poet/PropertySpecBuilder.kt | 1 + .../main/kotlin/poet/TypeAliasSpecBuilder.kt | 1 + .../src/main/kotlin/poet/TypeSpecBuilder.kt | 1 + .../spec/DelegateListValueClassSpecTest.kt | 38 ++++++ .../kotlin/spec/KotlinExceptionClassTest.kt | 6 +- 34 files changed, 973 insertions(+), 261 deletions(-) create mode 100644 _itest/builder-itest/src/test/kotlin/DelegateStringListITest.kt create mode 100644 _itest/builder-itest/src/test/kotlin/DelegateStringLongMapITest.kt create mode 100644 _itest/builder-itest/src/test/kotlin/DummyExceptionITest.kt create mode 100644 kotlin-code-generation/src/main/kotlin/builder/extra/DelegateListValueClassSpecBuilder.kt create mode 100644 kotlin-code-generation/src/main/kotlin/builder/extra/DelegateMapValueClassSpecBuilder.kt create mode 100644 kotlin-code-generation/src/test/kotlin/spec/DelegateListValueClassSpecTest.kt diff --git a/_itest/builder-itest/src/test/kotlin/DelegateStringListITest.kt b/_itest/builder-itest/src/test/kotlin/DelegateStringListITest.kt new file mode 100644 index 0000000..8375d68 --- /dev/null +++ b/_itest/builder-itest/src/test/kotlin/DelegateStringListITest.kt @@ -0,0 +1,41 @@ +package io.toolisticon.kotlin.generation.itest + +import com.squareup.kotlinpoet.ExperimentalKotlinPoetApi +import com.tschuchort.compiletesting.KotlinCompilation +import io.toolisticon.kotlin.generation.KotlinCodeGeneration +import io.toolisticon.kotlin.generation.itest.KotlinCodeGenerationITestConfig.ROOT_PACKAGE +import io.toolisticon.kotlin.generation.spec.toFileSpec +import io.toolisticon.kotlin.generation.test.KotlinCodeGenerationTest +import io.toolisticon.kotlin.generation.test.model.KotlinCompilationCommand +import org.assertj.core.api.Assertions.assertThat +import org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi +import org.junit.jupiter.api.Test +import kotlin.reflect.KClass +import kotlin.reflect.full.primaryConstructor +import io.toolisticon.kotlin.generation.test.KotlinCodeGenerationTest.assertThat as compileAssertThat + +@Suppress("UNCHECKED_CAST") +@OptIn(ExperimentalKotlinPoetApi::class, ExperimentalCompilerApi::class) +internal class DelegateStringListITest { + + @Test + fun `create and use string list`() { + val list = KotlinCodeGeneration.buildDelegateListValueClass(ROOT_PACKAGE, "StringList", String::class) { + propertyName("list") + }.toFileSpec() + + val result = KotlinCodeGenerationTest.compile(KotlinCompilationCommand(list)) + + + compileAssertThat(result).errorMessages().isEmpty() + compileAssertThat(result).hasExitCode(KotlinCompilation.ExitCode.OK) + + val klass: KClass = result.loadClass(list.className) + + val values = listOf("a", "b", "c") + + val instance: List = klass.primaryConstructor!!.call(values) as List + + assertThat(instance).hasToString("StringList(list=[a, b, c])") + } +} diff --git a/_itest/builder-itest/src/test/kotlin/DelegateStringLongMapITest.kt b/_itest/builder-itest/src/test/kotlin/DelegateStringLongMapITest.kt new file mode 100644 index 0000000..cc732a1 --- /dev/null +++ b/_itest/builder-itest/src/test/kotlin/DelegateStringLongMapITest.kt @@ -0,0 +1,44 @@ +package io.toolisticon.kotlin.generation.itest + +import com.squareup.kotlinpoet.ExperimentalKotlinPoetApi +import com.squareup.kotlinpoet.asTypeName +import com.tschuchort.compiletesting.KotlinCompilation +import io.toolisticon.kotlin.generation.KotlinCodeGeneration +import io.toolisticon.kotlin.generation.itest.KotlinCodeGenerationITestConfig.ROOT_PACKAGE +import io.toolisticon.kotlin.generation.spec.toFileSpec +import io.toolisticon.kotlin.generation.test.KotlinCodeGenerationTest +import io.toolisticon.kotlin.generation.test.model.KotlinCompilationCommand +import org.assertj.core.api.Assertions.assertThat +import org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi +import org.junit.jupiter.api.Test +import kotlin.reflect.KClass +import kotlin.reflect.full.primaryConstructor +import io.toolisticon.kotlin.generation.test.KotlinCodeGenerationTest.assertThat as compileAssertThat + +@Suppress("UNCHECKED_CAST") +@OptIn(ExperimentalKotlinPoetApi::class, ExperimentalCompilerApi::class) +internal class DelegateStringLongMapITest { + + @Test + fun `create and use string long map`() { + val map = KotlinCodeGeneration.buildDelegateMapValueClass( + packageName = ROOT_PACKAGE, + simpleName = "StringLongMap", + valueType = Long::class.asTypeName() + ) { + propertyName("map") + }.toFileSpec() + + val result = KotlinCodeGenerationTest.compile(KotlinCompilationCommand(map)) + compileAssertThat(result).errorMessages().isEmpty() + compileAssertThat(result).hasExitCode(KotlinCompilation.ExitCode.OK) + + val klass: KClass = result.loadClass(map.className) + + val values = mapOf("a" to 1, "b" to 2, "c" to 3) + + val instance: Map = klass.primaryConstructor!!.call(values) as Map + + assertThat(instance).hasToString("StringLongMap(map={a=1, b=2, c=3})") + } +} diff --git a/_itest/builder-itest/src/test/kotlin/DummyExceptionITest.kt b/_itest/builder-itest/src/test/kotlin/DummyExceptionITest.kt new file mode 100644 index 0000000..70093a6 --- /dev/null +++ b/_itest/builder-itest/src/test/kotlin/DummyExceptionITest.kt @@ -0,0 +1,52 @@ +package io.toolisticon.kotlin.generation.itest + +import com.squareup.kotlinpoet.ExperimentalKotlinPoetApi +import com.tschuchort.compiletesting.KotlinCompilation +import io.toolisticon.kotlin.generation.KotlinCodeGeneration.buildRuntimeExceptionClass +import io.toolisticon.kotlin.generation.itest.KotlinCodeGenerationITestConfig.ROOT_PACKAGE +import io.toolisticon.kotlin.generation.spec.toFileSpec +import io.toolisticon.kotlin.generation.test.KotlinCodeGenerationTest +import io.toolisticon.kotlin.generation.test.model.KotlinCompilationCommand +import org.assertj.core.api.Assertions.assertThat +import org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi +import org.junit.jupiter.api.Test +import kotlin.reflect.KClass +import kotlin.reflect.KProperty1 +import kotlin.reflect.full.memberProperties +import kotlin.reflect.full.primaryConstructor +import io.toolisticon.kotlin.generation.test.KotlinCodeGenerationTest.assertThat as compileAssertThat + +@OptIn(ExperimentalKotlinPoetApi::class, ExperimentalCompilerApi::class) +internal class DummyExceptionITest { + + @Test + fun `generate and create dummy exception`() { + val exceptionFile = buildRuntimeExceptionClass(ROOT_PACKAGE, "DummyException") { + messageTemplate("Dummy exception: expected: \$expected, actual: '\$actual'.") + addConstructorProperty("expected", Boolean::class) + addParameter("actual", String::class) + includeCause() + }.toFileSpec() + + + val result = KotlinCodeGenerationTest.compile(KotlinCompilationCommand(exceptionFile)) + + compileAssertThat(result).errorMessages().isEmpty() + compileAssertThat(result).hasExitCode(KotlinCompilation.ExitCode.OK) + + val c: KClass = result.loadClass(exceptionFile.className) + + val cause = IllegalStateException("foo") + val e: RuntimeException = c.primaryConstructor!!.call(true, "false", cause) as RuntimeException + + assertThat(e.localizedMessage).isEqualTo("Dummy exception: expected: true, actual: 'false'.") + + // TODO try to get value via pure kotlin without falling back to java + val expectedProperty: KProperty1 = c.memberProperties.single { it.name == "expected" } + val field = c.java.getDeclaredField("expected").apply { isAccessible = true } + + val expectedValue = field.get(e) as Boolean + + assertThat(expectedValue).isTrue() + } +} diff --git a/_itest/builder-itest/src/test/kotlin/HelloWorldExampleITest.kt b/_itest/builder-itest/src/test/kotlin/HelloWorldExampleITest.kt index 9f7511c..b88e1d7 100644 --- a/_itest/builder-itest/src/test/kotlin/HelloWorldExampleITest.kt +++ b/_itest/builder-itest/src/test/kotlin/HelloWorldExampleITest.kt @@ -34,7 +34,6 @@ internal class HelloWorldExampleITest { val file = buildFile(name) { addType(type) } - println(file.code) assertThat(file.packageName).isEqualTo("foo.bar") diff --git a/kotlin-code-generation/src/main/kotlin/KotlinCodeGeneration.kt b/kotlin-code-generation/src/main/kotlin/KotlinCodeGeneration.kt index 59cb7ac..1e62afd 100644 --- a/kotlin-code-generation/src/main/kotlin/KotlinCodeGeneration.kt +++ b/kotlin-code-generation/src/main/kotlin/KotlinCodeGeneration.kt @@ -1,4 +1,4 @@ -@file:Suppress(SUPPRESS_UNUSED) +@file:Suppress("unused") package io.toolisticon.kotlin.generation @@ -10,6 +10,8 @@ import io.toolisticon.kotlin.generation.KotlinCodeGeneration.builder.anonymousCl import io.toolisticon.kotlin.generation.KotlinCodeGeneration.builder.classBuilder import io.toolisticon.kotlin.generation.KotlinCodeGeneration.builder.companionObjectBuilder import io.toolisticon.kotlin.generation.KotlinCodeGeneration.builder.constructorPropertyBuilder +import io.toolisticon.kotlin.generation.KotlinCodeGeneration.builder.delegateListValueClassBuilder +import io.toolisticon.kotlin.generation.KotlinCodeGeneration.builder.delegateMapValueClassBuilder import io.toolisticon.kotlin.generation.KotlinCodeGeneration.builder.fileBuilder import io.toolisticon.kotlin.generation.KotlinCodeGeneration.builder.funBuilder import io.toolisticon.kotlin.generation.KotlinCodeGeneration.builder.interfaceBuilder @@ -19,9 +21,10 @@ import io.toolisticon.kotlin.generation.KotlinCodeGeneration.builder.propertyBui import io.toolisticon.kotlin.generation.KotlinCodeGeneration.builder.runtimeExceptionClassBuilder import io.toolisticon.kotlin.generation.KotlinCodeGeneration.builder.typeAliasBuilder import io.toolisticon.kotlin.generation.KotlinCodeGeneration.builder.valueClassBuilder +import io.toolisticon.kotlin.generation.KotlinCodeGeneration.className import io.toolisticon.kotlin.generation.builder.* -import io.toolisticon.kotlin.generation.builder.extra.RuntimeExceptionSpecBuilder -import io.toolisticon.kotlin.generation.builder.extra.RuntimeExceptionSpecBuilderReceiver +import io.toolisticon.kotlin.generation.builder.extra.* +import io.toolisticon.kotlin.generation.builder.extra.DelegateMapValueClassSpecBuilder.Companion.DEFAULT_KEY_TYPE import io.toolisticon.kotlin.generation.poet.FormatSpecifier.asCodeBlock import io.toolisticon.kotlin.generation.spec.* import io.toolisticon.kotlin.generation.spi.KotlinCodeGenerationContext @@ -29,9 +32,7 @@ import io.toolisticon.kotlin.generation.spi.KotlinCodeGenerationSpiRegistry import io.toolisticon.kotlin.generation.spi.registry.KotlinCodeGenerationServiceLoader import io.toolisticon.kotlin.generation.spi.strategy.KotlinFileSpecStrategy import io.toolisticon.kotlin.generation.spi.strategy.executeAll -import io.toolisticon.kotlin.generation.support.SUPPRESS_CLASS_NAME import io.toolisticon.kotlin.generation.support.SUPPRESS_MEMBER_VISIBILITY_CAN_BE_PRIVATE -import io.toolisticon.kotlin.generation.support.SUPPRESS_UNUSED import mu.KLogging import kotlin.reflect.KClass @@ -57,13 +58,14 @@ object KotlinCodeGeneration : KLogging() { * Build a [KotlinAnnotationClassSpec] using given className and receiver fn. * @see [KotlinAnnotationClassSpecBuilder.builder] */ - inline fun buildAnnotationClass(className: ClassName, block: KotlinAnnotationClassSpecBuilderReceiver = {}): KotlinAnnotationClassSpec = annotationClassBuilder(className).also(block).build() + inline fun buildAnnotationClass(className: ClassName, block: KotlinAnnotationClassSpecBuilderReceiver = {}) = annotationClassBuilder(className).also(block).build() /** * Build a [KotlinAnnotationClassSpec] using given package- and simpleName and receiver fn. * @see [KotlinAnnotationClassSpecBuilder.builder] */ - inline fun buildAnnotationClass(packageName: PackageName, simpleName: SimpleName, block: KotlinAnnotationClassSpecBuilderReceiver = {}): KotlinAnnotationClassSpec = buildAnnotationClass(className(packageName, simpleName), block) + @SuppressWarnings("unused") + inline fun buildAnnotationClass(packageName: PackageName, simpleName: SimpleName, block: KotlinAnnotationClassSpecBuilderReceiver = {}) = buildAnnotationClass(className(packageName, simpleName), block) /** * Build a [KotlinAnonymousClassSpec] using given receiver fn. @@ -83,6 +85,62 @@ object KotlinCodeGeneration : KLogging() { */ inline fun buildClass(packageName: PackageName, simpleName: SimpleName, block: KotlinClassSpecBuilderReceiver = {}) = buildClass(className(packageName, simpleName), block) + /** + * @see [DelegateListValueClassSpecBuilder] + */ + inline fun buildDelegateListValueClass( + packageName: PackageName, + simpleName: SimpleName, + items: KClass<*>, + block: DelegateListValueClassSpecBuilderReceiver = {} + ) = buildDelegateListValueClass(className = className(packageName, simpleName), items = items.asTypeName(), block = block) + + /** + * @see [DelegateListValueClassSpecBuilder] + */ + inline fun buildDelegateListValueClass( + packageName: PackageName, + simpleName: SimpleName, + items: TypeName, + block: DelegateListValueClassSpecBuilderReceiver = {} + ) = delegateListValueClassBuilder( + className = className(packageName, simpleName), + items = items + ).also(block).build() + + + /** + * @see [DelegateListValueClassSpecBuilder] + */ + inline fun buildDelegateListValueClass( + className: ClassName, + items: TypeName, + block: DelegateListValueClassSpecBuilderReceiver = {} + ) = delegateListValueClassBuilder(className, items).also(block).build() + + + /** + * @see [DelegateMapValueClassSpecBuilder] + */ + inline fun buildDelegateMapValueClass( + packageName: PackageName, + simpleName: SimpleName, + keyType: TypeName = DEFAULT_KEY_TYPE, + valueType: TypeName, + block: DelegateMapValueClassSpecBuilderReceiver = {} + ) = buildDelegateMapValueClass(className(packageName, simpleName), keyType, valueType, block) + + + /** + * @see [DelegateMapValueClassSpecBuilder] + */ + inline fun buildDelegateMapValueClass( + className: ClassName, + keyType: TypeName = DEFAULT_KEY_TYPE, + valueType: TypeName, + block: DelegateMapValueClassSpecBuilderReceiver = {} + ) = delegateMapValueClassBuilder(className, keyType, valueType).also(block).build() + /** * @see RuntimeExceptionSpecBuilder */ @@ -102,6 +160,7 @@ object KotlinCodeGeneration : KLogging() { * Build codeBlock using receiver-fn. * @see [CodeBlock.of] */ + @SuppressWarnings("unused") inline fun buildCodeBlock(block: CodeBlock.Builder.() -> Unit): CodeBlock = CodeBlock.builder().also(block).build() /** @@ -144,6 +203,7 @@ object KotlinCodeGeneration : KLogging() { * Build [KotlinEnumClassSpec]. * @see [KotlinEnumClassSpecBuilder.builder] */ + @SuppressWarnings("unused") inline fun buildEnumClass(packageName: PackageName, simpleName: SimpleName, block: KotlinEnumClassSpecBuilderReceiver = {}) = buildEnumClass(className(packageName, simpleName), block) /** @@ -156,6 +216,7 @@ object KotlinCodeGeneration : KLogging() { * Build [KotlinFileSpec]. * @see [KotlinFileSpecBuilder.builder] */ + @SuppressWarnings("unused") inline fun buildFile(packageName: PackageName, simpleName: SimpleName, block: KotlinFileSpecBuilderReceiver = {}): KotlinFileSpec = buildFile(className(packageName, simpleName), block) /** @@ -174,6 +235,7 @@ object KotlinCodeGeneration : KLogging() { * Build [KotlinInterfaceSpec]. * @see [KotlinInterfaceSpecBuilder.builder] */ + @SuppressWarnings("unused") inline fun buildInterface(packageName: PackageName, simpleName: SimpleName, block: KotlinInterfaceSpecBuilderReceiver = {}): KotlinInterfaceSpec = buildInterface(className(packageName, simpleName), block) @@ -193,12 +255,13 @@ object KotlinCodeGeneration : KLogging() { * Build [KotlinParameterSpec]. * @see [KotlinParameterSpecBuilder.builder] */ - inline fun buildParameter(name: ParameterName, typeName: TypeName, block: KotlinParameterSpecBuilderReceiver = {}): KotlinParameterSpec = parameterBuilder(name, typeName).also(block).build() + inline fun buildParameter(name: ParameterName, typeName: TypeName, block: KotlinParameterSpecBuilderReceiver = {}) = parameterBuilder(name, typeName).also(block).build() /** * Build [KotlinParameterSpec]. * @see [KotlinParameterSpecBuilder.builder] */ + @SuppressWarnings("unused") inline fun buildParameter(name: ParameterName, type: KClass<*>, block: KotlinParameterSpecBuilderReceiver = {}): KotlinParameterSpec = buildParameter(name, type.asTypeName(), block) /** @@ -236,7 +299,7 @@ object KotlinCodeGeneration : KLogging() { * Static access for all builders. */ @ExperimentalKotlinPoetApi - @Suppress(SUPPRESS_CLASS_NAME, SUPPRESS_MEMBER_VISIBILITY_CAN_BE_PRIVATE) + @Suppress("ClassName", SUPPRESS_MEMBER_VISIBILITY_CAN_BE_PRIVATE) object builder { /** * @see KotlinAnnotationClassSpecBuilder @@ -246,6 +309,7 @@ object KotlinCodeGeneration : KLogging() { /** * @see KotlinAnnotationClassSpecBuilder */ + @SuppressWarnings("unused") fun annotationClassBuilder(packageName: PackageName, simpleName: SimpleName) = annotationClassBuilder(className(packageName, simpleName)) /** @@ -256,11 +320,13 @@ object KotlinCodeGeneration : KLogging() { /** * @see KotlinAnnotationSpecBuilder */ + @SuppressWarnings("unused") fun annotationBuilder(type: KClass) = annotationBuilder(type.asClassName()) /** * @see KotlinAnnotationSpecBuilder */ + @SuppressWarnings("unused") fun annotationBuilder(packageName: PackageName, simpleName: SimpleName) = annotationBuilder(className(packageName, simpleName)) /** @@ -301,16 +367,29 @@ object KotlinCodeGeneration : KLogging() { /** * @see KotlinDataClassSpecBuilder */ + @SuppressWarnings("unused") fun dataClassBuilder(packageName: PackageName, simpleName: SimpleName) = dataClassBuilder(className(packageName, simpleName)) + /** + * @see DelegateListValueClassSpecBuilder + */ + fun delegateListValueClassBuilder(className: ClassName, items: TypeName) = DelegateListValueClassSpecBuilder.builder(className, items) + + /** + * @see DelegateMapValueClassSpecBuilder + */ + fun delegateMapValueClassBuilder(className: ClassName, keyType: TypeName = DEFAULT_KEY_TYPE, valueType: TypeName) = DelegateMapValueClassSpecBuilder.builder(className, keyType, valueType) + /** * @see KotlinEnumClassSpecBuilder */ + @SuppressWarnings("unused") fun enumClassBuilder(name: SimpleName) = KotlinEnumClassSpecBuilder.builder(name) /** * @see KotlinEnumClassSpecBuilder */ + @SuppressWarnings("unused") fun enumClassBuilder(packageName: PackageName, name: SimpleName) = enumClassBuilder(className(packageName, name)) /** @@ -319,7 +398,7 @@ object KotlinCodeGeneration : KLogging() { fun enumClassBuilder(className: ClassName) = KotlinEnumClassSpecBuilder.builder(className) /** - * @see KotlinExceptionClassSpecBuilder + * @see RuntimeExceptionSpecBuilder */ fun runtimeExceptionClassBuilder(className: ClassName) = RuntimeExceptionSpecBuilder.builder(className) @@ -376,27 +455,29 @@ object KotlinCodeGeneration : KLogging() { /** * @see KotlinPropertySpecBuilder */ + @SuppressWarnings("unused") fun propertyBuilder(name: PropertyName, type: TypeName) = KotlinPropertySpecBuilder.builder(name, type) /** * @see KotlinPropertySpecBuilder */ + @SuppressWarnings("unused") fun propertyBuilder(name: PropertyName, type: KClass<*>) = propertyBuilder(name, type.asTypeName()) /** * @see KotlinFunSpecBuilder */ - fun setterBuilder(): KotlinFunSpecBuilder = KotlinFunSpecBuilder.setterBuilder() + fun setterBuilder() = KotlinFunSpecBuilder.setterBuilder() /** * @see KotlinTypeAliasSpecBuilder */ - fun typeAliasBuilder(name: TypeAliasName, type: TypeName): KotlinTypeAliasSpecBuilder = KotlinTypeAliasSpecBuilder.builder(name, type) + fun typeAliasBuilder(name: TypeAliasName, type: TypeName) = KotlinTypeAliasSpecBuilder.builder(name, type) /** * @see KotlinTypeAliasSpecBuilder */ - fun typeAliasBuilder(name: String, type: KClass<*>): KotlinTypeAliasSpecBuilder = KotlinTypeAliasSpecBuilder.builder(name, type) + fun typeAliasBuilder(name: String, type: KClass<*>) = KotlinTypeAliasSpecBuilder.builder(name, type) /** * @see KotlinValueClassSpecBuilder @@ -406,6 +487,7 @@ object KotlinCodeGeneration : KLogging() { /** * @see KotlinValueClassSpecBuilder */ + @SuppressWarnings("unused") fun valueClassBuilder(packageName: PackageName, simpleName: SimpleName) = valueClassBuilder(className(packageName, simpleName)) } @@ -422,7 +504,7 @@ object KotlinCodeGeneration : KLogging() { /** * Static to spi. */ - @Suppress(SUPPRESS_CLASS_NAME) + @Suppress("ClassName") object spi { /** * The default classLoader supplier fn. @@ -442,7 +524,7 @@ object KotlinCodeGeneration : KLogging() { /** * TypeSpec helpers. */ - @Suppress(SUPPRESS_CLASS_NAME) + @Suppress("ClassName") object typeSpec { fun TypeSpec.hasModifier(modifier: KModifier) = this.modifiers.contains(modifier) @@ -451,7 +533,7 @@ object KotlinCodeGeneration : KLogging() { val TypeSpec.isValueClass: Boolean get() = hasModifier(KModifier.VALUE) } - @Suppress(SUPPRESS_CLASS_NAME) + @Suppress("ClassName") object name { fun Collection.asCodeBlock(): CodeBlock = this.map { it.asCodeBlock() }.joinToCode(prefix = "[", suffix = "]") @@ -463,7 +545,7 @@ object KotlinCodeGeneration : KLogging() { /** * Constants for kotlin-poet formats. */ - @Suppress(SUPPRESS_CLASS_NAME) + @Suppress("ClassName") object format { const val FORMAT_STRING = "%S" const val FORMAT_STRING_TEMPLATE = "%P" diff --git a/kotlin-code-generation/src/main/kotlin/builder/KotlinAnnotationClassSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/builder/KotlinAnnotationClassSpecBuilder.kt index 6df0adf..47d1ea3 100644 --- a/kotlin-code-generation/src/main/kotlin/builder/KotlinAnnotationClassSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/builder/KotlinAnnotationClassSpecBuilder.kt @@ -28,8 +28,14 @@ class KotlinAnnotationClassSpecBuilder internal constructor( companion object { + /** + * Creates new builder. + */ fun builder(name: String): KotlinAnnotationClassSpecBuilder = builder(simpleClassName(name)) + /** + * Creates new builder. + */ fun builder(className: ClassName): KotlinAnnotationClassSpecBuilder = KotlinAnnotationClassSpecBuilder(className = className) } @@ -41,31 +47,33 @@ class KotlinAnnotationClassSpecBuilder internal constructor( private var repeatable: Boolean = false private var mustBeDocumented: Boolean = false - + /** + * Add mustBeDocumented. + */ fun mustBeDocumented() = apply { this.mustBeDocumented = true } + + /** + * Add repeatable. + */ fun repeatable() = apply { this.repeatable = true } - fun target(vararg targets: AnnotationTarget) = apply { this.targets.addAll(targets) } - fun retention(retention: AnnotationRetention) = apply { - this._retention = retention - } + /** + * Add retention. + */ + fun retention(retention: AnnotationRetention) = apply { this._retention = retention } - override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec.get()) } - override fun addConstructorProperty(spec: KotlinConstructorPropertySpecSupplier) = apply { constructorProperties[spec.name] = spec } - override fun contextReceivers(vararg receiverTypes: TypeName) = builder { this.contextReceivers(*receiverTypes) } - override fun addFunction(funSpec: KotlinFunSpecSupplier) = apply { delegate.addFunction(funSpec.get()) } - override fun addKdoc(kdoc: KDoc) = apply { delegate.addKdoc(kdoc.get()) } - override fun addModifiers(vararg modifiers: KModifier) = builder { this.addModifiers(*modifiers) } - override fun addProperty(propertySpec: KotlinPropertySpecSupplier) = apply { delegate.addProperty(propertySpec.get()) } - override fun addType(typeSpec: TypeSpecSupplier) = builder { this.addType(typeSpec.get()) } - override fun tag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } + /** + * Add target. + */ + fun target(vararg targets: AnnotationTarget) = apply { this.targets.addAll(targets) } - fun addOriginatingElement(originatingElement: Element) = builder { this.addOriginatingElement(originatingElement) } - override fun builder(block: TypeSpecBuilderReceiver) = apply { delegate.builder.block() } + internal fun addOriginatingElement(originatingElement: Element) = builder { this.addOriginatingElement(originatingElement) } + override fun build(): KotlinAnnotationClassSpec { if (constructorProperties.isNotEmpty()) { - delegate.primaryConstructorWithProperties(toList(constructorProperties.values)) + val constructor = delegate.primaryConstructorWithProperties(toList(constructorProperties.values)) + delegate.primaryConstructor(constructor.build()) } if (targets.isNotEmpty()) { delegate.addAnnotation(buildAnnotation(Target::class) { @@ -87,6 +95,19 @@ class KotlinAnnotationClassSpecBuilder internal constructor( return KotlinAnnotationClassSpec(className = className, spec = delegate.build()) } + + // + override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec.get()) } + override fun addConstructorProperty(spec: KotlinConstructorPropertySpecSupplier) = apply { constructorProperties[spec.name] = spec } + override fun contextReceivers(vararg receiverTypes: TypeName) = builder { this.contextReceivers(*receiverTypes) } + override fun addFunction(funSpec: KotlinFunSpecSupplier) = apply { delegate.addFunction(funSpec.get()) } + override fun addKdoc(kdoc: KDoc) = apply { delegate.addKdoc(kdoc.get()) } + override fun addModifiers(vararg modifiers: KModifier) = builder { this.addModifiers(*modifiers) } + override fun addProperty(propertySpec: KotlinPropertySpecSupplier) = apply { delegate.addProperty(propertySpec.get()) } + override fun addType(typeSpec: TypeSpecSupplier) = builder { this.addType(typeSpec.get()) } + override fun addTag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } + override fun builder(block: TypeSpecBuilderReceiver) = apply { delegate.builder.block() } + // } @ExperimentalKotlinPoetApi diff --git a/kotlin-code-generation/src/main/kotlin/builder/KotlinAnnotationSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/builder/KotlinAnnotationSpecBuilder.kt index 6468976..2ac80b6 100644 --- a/kotlin-code-generation/src/main/kotlin/builder/KotlinAnnotationSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/builder/KotlinAnnotationSpecBuilder.kt @@ -35,16 +35,29 @@ class KotlinAnnotationSpecBuilder internal constructor( DelegatingBuilder { companion object { + + /** + * Creates new builder. + */ fun builder(type: ClassName): KotlinAnnotationSpecBuilder = KotlinAnnotationSpecBuilder( delegate = AnnotationSpecBuilder.builder(type) ) + /** + * Creates new builder. + */ fun builder(type: ParameterizedTypeName): KotlinAnnotationSpecBuilder = KotlinAnnotationSpecBuilder( delegate = AnnotationSpecBuilder.builder(type) ) + /** + * Creates new builder. + */ fun builder(type: KClass): KotlinAnnotationSpecBuilder = builder(type.asClassName()) + /** + * Creates new builder from spec. + */ fun from(spec: KotlinAnnotationSpecSupplier) = KotlinAnnotationSpecBuilder( delegate = spec.get().toBuilder().wrap() ) @@ -69,31 +82,71 @@ class KotlinAnnotationSpecBuilder internal constructor( private var multiLine = false private val members: MutableList = mutableListOf() - override fun tag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } - + /** + * If marked multiline all members become a new line. + */ fun multiLine() = apply { multiLine = true } + /** + * Add member to annotation. + */ fun addMember(codeBlock: CodeBlock): KotlinAnnotationSpecBuilder = apply { members.add(codeBlock) } + /** + * Add member to annotation. + */ fun addMember(format: String, vararg args: Any): KotlinAnnotationSpecBuilder = addMember(buildCodeBlock(format, *args)) + /** + * Add member to annotation. + */ fun addNameMember(memberName: MemberName): KotlinAnnotationSpecBuilder = addMember("%M", memberName) + /** + * Add member to annotation. + */ fun addKClassMember(name: String, value: KClass<*>) = addMember(member.kclass(name, value)) + + /** + * Add member to annotation. + */ fun addKClassMembers(name: String, vararg values: KClass<*>) = addMember(member.kclasses(name, *values)) + /** + * Add member to annotation. + */ fun addStringMember(name: String, value: String) = addMember(member.string(name, value)) + + /** + * Add member to annotation. + */ fun addStringMembers(name: String, vararg values: String) = addMember(member.strings(name, *values)) + /** + * Add member to annotation. + */ fun addEnumMember(name: String, value: Enum<*>): KotlinAnnotationSpecBuilder = addMember(member.enum(name, value)) + + /** + * Add member to annotation. + */ fun addEnumMembers(name: String, vararg values: Enum<*>): KotlinAnnotationSpecBuilder = addMember(member.enums(name, *values)) + /** + * Add member to annotation. + */ fun addNumberMember(name: String, value: Number): KotlinAnnotationSpecBuilder = addMember(member.number(name, value)) + + /** + * Add member to annotation. + */ fun addNumberMembers(name: String, vararg values: Number): KotlinAnnotationSpecBuilder = addMember(member.numbers(name, *values)) + /** + * Remove all members. + */ fun clearMembers() = apply { members.clear() } - override fun builder(block: AnnotationSpecBuilderReceiver) = apply { delegate.builder.block() } override fun build(): KotlinAnnotationSpec { if (members.isNotEmpty()) { @@ -106,8 +159,12 @@ class KotlinAnnotationSpecBuilder internal constructor( return KotlinAnnotationSpec(spec = delegate.build()) } - override fun spec(): KotlinAnnotationSpec = build() + // + override fun addTag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } + override fun builder(block: AnnotationSpecBuilderReceiver) = apply { delegate.builder.block() } override fun get(): AnnotationSpec = build().get() + override fun spec(): KotlinAnnotationSpec = build() + // } @ExperimentalKotlinPoetApi diff --git a/kotlin-code-generation/src/main/kotlin/builder/KotlinAnonymousClassSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/builder/KotlinAnonymousClassSpecBuilder.kt index 88fb3e3..4858d82 100644 --- a/kotlin-code-generation/src/main/kotlin/builder/KotlinAnonymousClassSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/builder/KotlinAnonymousClassSpecBuilder.kt @@ -27,37 +27,43 @@ class KotlinAnonymousClassSpecBuilder internal constructor( DelegatingBuilder { companion object { + /** + * Creates new builder. + */ fun builder(): KotlinAnonymousClassSpecBuilder = KotlinAnonymousClassSpecBuilder() } internal constructor() : this(delegate = TypeSpecBuilder.anonymousClassBuilder()) - override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec.get()) } - override fun contextReceivers(vararg receiverTypes: TypeName) = builder { this.contextReceivers(*receiverTypes) } - override fun addFunction(funSpec: KotlinFunSpecSupplier) = apply { delegate.addFunction(funSpec.get()) } - override fun addKdoc(kdoc: KDoc) = apply { delegate.addKdoc(kdoc.get()) } - override fun addModifiers(vararg modifiers: KModifier) = builder { this.addModifiers(*modifiers) } - override fun addProperty(propertySpec: KotlinPropertySpecSupplier) = apply { delegate.addProperty(propertySpec.get()) } - override fun addType(typeSpec: TypeSpecSupplier) = builder { this.addType(typeSpec.get()) } - override fun tag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } - - fun addOriginatingElement(originatingElement: Element) = builder { this.addOriginatingElement(originatingElement) } + internal fun addOriginatingElement(originatingElement: Element) = builder { this.addOriginatingElement(originatingElement) } fun addTypeVariable(typeVariable: TypeVariableName) = builder { this.addTypeVariable(typeVariable) } + fun primaryConstructor(primaryConstructor: FunSpecSupplier?) = builder { this.primaryConstructor(primaryConstructor?.get()) } + fun superclass(superclass: TypeName) = builder { this.superclass(superclass) } fun superclass(superclass: KClass<*>) = builder { this.superclass(superclass) } fun addSuperclassConstructorParameter(format: String, vararg args: Any) = builder { this.addSuperclassConstructorParameter(format, *args) } fun addSuperclassConstructorParameter(codeBlock: CodeBlock) = builder { this.addSuperclassConstructorParameter(codeBlock) } - override fun addSuperinterface(superinterface: TypeName, constructorParameter: String) = builder { this.addSuperinterface(superinterface, constructorParameter) } - override fun addSuperinterface(superinterface: TypeName, delegate: CodeBlock) = builder { this.addSuperinterface(superinterface, delegate) } - fun addInitializerBlock(block: CodeBlock) = builder { this.addInitializerBlock(block) } - override fun builder(block: TypeSpecBuilderReceiver) = apply { delegate.builder.block() } override fun build(): KotlinAnonymousClassSpec = KotlinAnonymousClassSpec(delegate.build()) + + // + override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec.get()) } + override fun contextReceivers(vararg receiverTypes: TypeName) = builder { this.contextReceivers(*receiverTypes) } + override fun addFunction(funSpec: KotlinFunSpecSupplier) = apply { delegate.addFunction(funSpec.get()) } + override fun addKdoc(kdoc: KDoc) = apply { delegate.addKdoc(kdoc.get()) } + override fun addModifiers(vararg modifiers: KModifier) = builder { this.addModifiers(*modifiers) } + override fun addProperty(propertySpec: KotlinPropertySpecSupplier) = apply { delegate.addProperty(propertySpec.get()) } + override fun addSuperinterface(superinterface: TypeName, constructorParameter: String) = builder { this.addSuperinterface(superinterface, constructorParameter) } + override fun addSuperinterface(superinterface: TypeName, delegate: CodeBlock) = builder { this.addSuperinterface(superinterface, delegate) } + override fun addType(typeSpec: TypeSpecSupplier) = builder { this.addType(typeSpec.get()) } + override fun addTag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } + override fun builder(block: TypeSpecBuilderReceiver) = apply { delegate.builder.block() } + // } @ExperimentalKotlinPoetApi diff --git a/kotlin-code-generation/src/main/kotlin/builder/KotlinClassSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/builder/KotlinClassSpecBuilder.kt index 5c5bd77..dc2f057 100644 --- a/kotlin-code-generation/src/main/kotlin/builder/KotlinClassSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/builder/KotlinClassSpecBuilder.kt @@ -4,6 +4,7 @@ package io.toolisticon.kotlin.generation.builder import com.squareup.kotlinpoet.* import io.toolisticon.kotlin.generation.KotlinCodeGeneration.simpleClassName +import io.toolisticon.kotlin.generation.PropertyName import io.toolisticon.kotlin.generation.builder.KotlinConstructorPropertySpecBuilder.Companion.primaryConstructorWithProperties import io.toolisticon.kotlin.generation.poet.* import io.toolisticon.kotlin.generation.spec.* @@ -17,7 +18,7 @@ import kotlin.reflect.KClass @ExperimentalKotlinPoetApi class KotlinClassSpecBuilder internal constructor( internal val className: ClassName, - private val delegate: TypeSpecBuilder + internal val delegate: TypeSpecBuilder ) : KotlinGeneratorTypeSpecBuilder, KotlinAnnotatableDocumentableModifiableBuilder, KotlinConstructorPropertySupport, @@ -27,27 +28,23 @@ class KotlinClassSpecBuilder internal constructor( KotlinTypeSpecHolderBuilder { companion object { + /** + * Creates new builder. + */ fun builder(name: String): KotlinClassSpecBuilder = builder(simpleClassName(name)) + + /** + * Creates new builder. + */ fun builder(className: ClassName): KotlinClassSpecBuilder = KotlinClassSpecBuilder(className = className) } internal constructor(className: ClassName) : this(className, TypeSpecBuilder.classBuilder(className)) - private val constructorProperties: LinkedHashMap = LinkedHashMap() + internal val constructorProperties: LinkedHashMap = LinkedHashMap() private var isSetPrimaryConstructor: Boolean = false - override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec.get()) } - override fun addConstructorProperty(spec: KotlinConstructorPropertySpecSupplier) = apply { constructorProperties[spec.name] = spec } - override fun contextReceivers(vararg receiverTypes: TypeName) = builder { this.contextReceivers(*receiverTypes) } - override fun addFunction(funSpec: KotlinFunSpecSupplier) = apply { delegate.addFunction(funSpec.get()) } - override fun addKdoc(kdoc: KDoc) = apply { delegate.addKdoc(kdoc.get()) } - override fun addModifiers(vararg modifiers: KModifier) = builder { this.addModifiers(*modifiers) } - override fun addProperty(propertySpec: KotlinPropertySpecSupplier) = apply { delegate.addProperty(propertySpec.get()) } - override fun addSuperinterface(superinterface: TypeName, constructorParameter: String) = builder { this.addSuperinterface(superinterface, constructorParameter) } - override fun addSuperinterface(superinterface: TypeName, delegate: CodeBlock) = builder { this.addSuperinterface(superinterface, delegate) } - override fun addType(typeSpec: TypeSpecSupplier) = builder { this.addType(typeSpec.get()) } - override fun tag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } - fun addOriginatingElement(originatingElement: Element) = builder { this.addOriginatingElement(originatingElement) } + internal fun addOriginatingElement(originatingElement: Element) = builder { this.addOriginatingElement(originatingElement) } fun addTypeVariable(typeVariable: TypeVariableName) = builder { this.addTypeVariable(typeVariable) } fun primaryConstructor(primaryConstructor: FunSpecSupplier?) = apply { @@ -66,17 +63,32 @@ class KotlinClassSpecBuilder internal constructor( fun addInitializerBlock(block: CodeBlock) = builder { this.addInitializerBlock(block) } - override fun builder(block: TypeSpecBuilderReceiver) = apply { delegate.builder.block() } override fun build(): KotlinClassSpec { val hasConstructorProperties = constructorProperties.isNotEmpty() - check(!(hasConstructorProperties && isSetPrimaryConstructor)) { "Decide if you want to use the constructorProperty support OR define a custom primary constructor, not both." } + check( !(hasConstructorProperties && isSetPrimaryConstructor)) { "Decide if you want to use the constructorProperty support OR define a custom primary constructor, not both." } if (hasConstructorProperties) { - delegate.primaryConstructorWithProperties(toList(constructorProperties.values)) + val constructor = delegate.primaryConstructorWithProperties(toList(constructorProperties.values)) + delegate.primaryConstructor(constructor.build()) } return KotlinClassSpec(className = className, spec = delegate.build()) } + + // + override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec.get()) } + override fun addConstructorProperty(spec: KotlinConstructorPropertySpecSupplier) = apply { constructorProperties[spec.name] = spec } + override fun contextReceivers(vararg receiverTypes: TypeName) = builder { this.contextReceivers(*receiverTypes) } + override fun addFunction(funSpec: KotlinFunSpecSupplier) = apply { delegate.addFunction(funSpec.get()) } + override fun addKdoc(kdoc: KDoc) = apply { delegate.addKdoc(kdoc.get()) } + override fun addModifiers(vararg modifiers: KModifier) = builder { this.addModifiers(*modifiers) } + override fun addProperty(propertySpec: KotlinPropertySpecSupplier) = apply { delegate.addProperty(propertySpec.get()) } + override fun addSuperinterface(superinterface: TypeName, constructorParameter: String) = builder { this.addSuperinterface(superinterface, constructorParameter) } + override fun addSuperinterface(superinterface: TypeName, delegate: CodeBlock) = builder { this.addSuperinterface(superinterface, delegate) } + override fun addType(typeSpec: TypeSpecSupplier) = builder { this.addType(typeSpec.get()) } + override fun addTag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } + override fun builder(block: TypeSpecBuilderReceiver) = apply { delegate.builder.block() } + // } @ExperimentalKotlinPoetApi diff --git a/kotlin-code-generation/src/main/kotlin/builder/KotlinCompanionObjectSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/builder/KotlinCompanionObjectSpecBuilder.kt index 50fbd0a..ca15fe4 100644 --- a/kotlin-code-generation/src/main/kotlin/builder/KotlinCompanionObjectSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/builder/KotlinCompanionObjectSpecBuilder.kt @@ -28,21 +28,15 @@ class KotlinCompanionObjectSpecBuilder internal constructor( KotlinTypeSpecHolderBuilder { companion object { + /** + * Creates new builder. + */ fun builder(name: String? = null): KotlinCompanionObjectSpecBuilder = KotlinCompanionObjectSpecBuilder(name) } internal constructor(name: String? = null) : this(TypeSpecBuilder.Companion.companionObjectBuilder(name)) - override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec.get()) } - override fun contextReceivers(vararg receiverTypes: TypeName) = builder { delegate.contextReceivers(*receiverTypes) } - override fun addFunction(funSpec: KotlinFunSpecSupplier) = apply { delegate.addFunction(funSpec.get()) } - override fun addKdoc(kdoc: KDoc) = apply { delegate.addKdoc(kdoc.get()) } - override fun addModifiers(vararg modifiers: KModifier) = builder { delegate.addModifiers(*modifiers) } - override fun addProperty(propertySpec: KotlinPropertySpecSupplier) = apply { delegate.addProperty(propertySpec.get()) } - override fun addType(typeSpec: TypeSpecSupplier) = builder { delegate.addType(typeSpec.get()) } - override fun tag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } - - fun addOriginatingElement(originatingElement: Element) = builder { + internal fun addOriginatingElement(originatingElement: Element) = builder { delegate.addOriginatingElement( originatingElement ) @@ -55,29 +49,23 @@ class KotlinCompanionObjectSpecBuilder internal constructor( ) } - fun superclass(superclass: TypeName) = builder { delegate.superclass(superclass) } - fun superclass(superclass: KClass<*>) = builder { delegate.superclass(superclass) } - - fun addSuperclassConstructorParameter(format: String, vararg args: Any) = builder { - delegate.addSuperclassConstructorParameter( - format, - *args - ) - } + fun addInitializerBlock(block: CodeBlock) = builder { delegate.addInitializerBlock(block) } - fun addSuperclassConstructorParameter(codeBlock: CodeBlock) = builder { - delegate.addSuperclassConstructorParameter( - codeBlock - ) - } + override fun build(): KotlinCompanionObjectSpec = KotlinCompanionObjectSpec(spec = delegate.build()) + // + override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec.get()) } + override fun contextReceivers(vararg receiverTypes: TypeName) = builder { delegate.contextReceivers(*receiverTypes) } + override fun addFunction(funSpec: KotlinFunSpecSupplier) = apply { delegate.addFunction(funSpec.get()) } + override fun addKdoc(kdoc: KDoc) = apply { delegate.addKdoc(kdoc.get()) } + override fun addModifiers(vararg modifiers: KModifier) = builder { delegate.addModifiers(*modifiers) } + override fun addProperty(propertySpec: KotlinPropertySpecSupplier) = apply { delegate.addProperty(propertySpec.get()) } override fun addSuperinterface(superinterface: TypeName, constructorParameter: String) = builder { this.addSuperinterface(superinterface, constructorParameter) } override fun addSuperinterface(superinterface: TypeName, delegate: CodeBlock) = builder { this.addSuperinterface(superinterface, delegate) } - - fun addInitializerBlock(block: CodeBlock) = builder { delegate.addInitializerBlock(block) } - + override fun addType(typeSpec: TypeSpecSupplier) = builder { delegate.addType(typeSpec.get()) } + override fun addTag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } override fun builder(block: TypeSpecBuilderReceiver) = apply { delegate.builder.block() } - override fun build(): KotlinCompanionObjectSpec = KotlinCompanionObjectSpec(spec = delegate.build()) + // } @ExperimentalKotlinPoetApi diff --git a/kotlin-code-generation/src/main/kotlin/builder/KotlinConstructorPropertySpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/builder/KotlinConstructorPropertySpecBuilder.kt index b2045ee..6e4a297 100644 --- a/kotlin-code-generation/src/main/kotlin/builder/KotlinConstructorPropertySpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/builder/KotlinConstructorPropertySpecBuilder.kt @@ -1,15 +1,13 @@ package io.toolisticon.kotlin.generation.builder -import com.squareup.kotlinpoet.ExperimentalKotlinPoetApi -import com.squareup.kotlinpoet.FunSpec -import com.squareup.kotlinpoet.KModifier -import com.squareup.kotlinpoet.TypeName +import com.squareup.kotlinpoet.* import io.toolisticon.kotlin.generation.Builder +import io.toolisticon.kotlin.generation.poet.FunSpecBuilder +import io.toolisticon.kotlin.generation.poet.FunSpecBuilder.Companion.wrap import io.toolisticon.kotlin.generation.poet.KDoc import io.toolisticon.kotlin.generation.poet.TypeSpecBuilder -import io.toolisticon.kotlin.generation.spec.KotlinAnnotationSpecSupplier -import io.toolisticon.kotlin.generation.spec.KotlinConstructorPropertySpec -import io.toolisticon.kotlin.generation.spec.KotlinConstructorPropertySpecSupplier +import io.toolisticon.kotlin.generation.poet.TypeSpecSupplier +import io.toolisticon.kotlin.generation.spec.* import kotlin.reflect.KClass /** @@ -26,6 +24,10 @@ class KotlinConstructorPropertySpecBuilder internal constructor( KotlinConstructorPropertySpecSupplier { companion object { + + /** + * Creates new builder. + */ fun builder(name: String, type: TypeName): KotlinConstructorPropertySpecBuilder = KotlinConstructorPropertySpecBuilder( name = name, type = type, @@ -33,22 +35,17 @@ class KotlinConstructorPropertySpecBuilder internal constructor( parameterBuilder = KotlinParameterSpecBuilder.builder(name = name, type = type) ) - internal fun TypeSpecBuilder.primaryConstructorWithProperties(constructorProperties: List) { - val constructor = FunSpec.constructorBuilder() + internal fun TypeSpecBuilder.primaryConstructorWithProperties(constructorProperties: List): FunSpecBuilder { + val constructor = FunSpec.constructorBuilder().wrap() constructorProperties.forEach { constructor.addParameter(it.parameter.get()) this.addProperty(it.property.get()) } - this.primaryConstructor(constructor.build()) + return constructor } } - override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { parameterBuilder.addAnnotation(spec) } - override fun addKdoc(kdoc: KDoc) = apply { parameterBuilder.addKdoc(kdoc) } - override fun addModifiers(vararg modifiers: KModifier) = apply { propertyBuilder.addModifiers(*modifiers) } - override fun tag(type: KClass<*>, tag: Any?) = apply { propertyBuilder.tag(type, tag) } - override fun build(): KotlinConstructorPropertySpec { val parameter = parameterBuilder.build() val property = propertyBuilder @@ -60,7 +57,14 @@ class KotlinConstructorPropertySpecBuilder internal constructor( return KotlinConstructorPropertySpec(parameter = parameter, property = property) } + // + override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { parameterBuilder.addAnnotation(spec) } + override fun addKdoc(kdoc: KDoc) = apply { parameterBuilder.addKdoc(kdoc) } + override fun addModifiers(vararg modifiers: KModifier) = apply { propertyBuilder.addModifiers(*modifiers) } + override fun addTag(type: KClass<*>, tag: Any?) = apply { propertyBuilder.addTag(type, tag) } override fun spec(): KotlinConstructorPropertySpec = build() + // + } @ExperimentalKotlinPoetApi diff --git a/kotlin-code-generation/src/main/kotlin/builder/KotlinDataClassSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/builder/KotlinDataClassSpecBuilder.kt index 09db23e..4da498f 100644 --- a/kotlin-code-generation/src/main/kotlin/builder/KotlinDataClassSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/builder/KotlinDataClassSpecBuilder.kt @@ -27,7 +27,14 @@ class KotlinDataClassSpecBuilder internal constructor( KotlinSuperInterfaceSupport, KotlinTypeSpecHolderBuilder { companion object : KLogging() { + /** + * Creates new builder. + */ fun builder(name: String): KotlinDataClassSpecBuilder = builder(simpleClassName(name)) + + /** + * Creates new builder. + */ fun builder(className: ClassName): KotlinDataClassSpecBuilder = KotlinDataClassSpecBuilder(className) } @@ -42,33 +49,36 @@ class KotlinDataClassSpecBuilder internal constructor( private val constructorProperties = LinkedHashMap() - override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec.get()) } - override fun addConstructorProperty(spec: KotlinConstructorPropertySpecSupplier) = apply { this.constructorProperties[spec.name] = spec } - override fun contextReceivers(vararg receiverTypes: TypeName) = builder { this.contextReceivers(*receiverTypes) } - override fun addFunction(funSpec: KotlinFunSpecSupplier) = apply { delegate.addFunction(funSpec.get()) } - override fun addKdoc(kdoc: KDoc) = apply { delegate.addKdoc(kdoc.get()) } - override fun addModifiers(vararg modifiers: KModifier) = builder { this.addModifiers(*modifiers) } - override fun addProperty(propertySpec: KotlinPropertySpecSupplier) = apply { delegate.addProperty(propertySpec.get()) } - override fun addType(typeSpec: TypeSpecSupplier) = builder { this.addType(typeSpec.get()) } - override fun tag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } - fun addOriginatingElement(originatingElement: Element) = builder { this.addOriginatingElement(originatingElement) } + internal fun addOriginatingElement(originatingElement: Element) = builder { this.addOriginatingElement(originatingElement) } fun addTypeVariable(typeVariable: TypeVariableName) = builder { this.addTypeVariable(typeVariable) } fun primaryConstructor(primaryConstructor: FunSpecSupplier?) = builder { this.primaryConstructor(primaryConstructor?.get()) } - override fun addSuperinterface(superinterface: TypeName, constructorParameter: String) = builder { this.addSuperinterface(superinterface, constructorParameter) } - override fun addSuperinterface(superinterface: TypeName, delegate: CodeBlock) = builder { this.addSuperinterface(superinterface, delegate) } - fun addInitializerBlock(block: CodeBlock) = builder { this.addInitializerBlock(block) } - override fun builder(block: TypeSpecBuilderReceiver) = apply { delegate.builder.block() } override fun build(): KotlinDataClassSpec { check(constructorProperties.isNotEmpty()) { "Data class must have at least one property." } - delegate.primaryConstructorWithProperties(toList(constructorProperties.values)) + val constructor = delegate.primaryConstructorWithProperties(toList(constructorProperties.values)) + delegate.primaryConstructor(constructor.build()) return KotlinDataClassSpec(className = className, spec = delegate.build()) } + + // + override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec.get()) } + override fun addConstructorProperty(spec: KotlinConstructorPropertySpecSupplier) = apply { this.constructorProperties[spec.name] = spec } + override fun contextReceivers(vararg receiverTypes: TypeName) = builder { this.contextReceivers(*receiverTypes) } + override fun addFunction(funSpec: KotlinFunSpecSupplier) = apply { delegate.addFunction(funSpec.get()) } + override fun addKdoc(kdoc: KDoc) = apply { delegate.addKdoc(kdoc.get()) } + override fun addModifiers(vararg modifiers: KModifier) = builder { this.addModifiers(*modifiers) } + override fun addProperty(propertySpec: KotlinPropertySpecSupplier) = apply { delegate.addProperty(propertySpec.get()) } + override fun addSuperinterface(superinterface: TypeName, constructorParameter: String) = builder { this.addSuperinterface(superinterface, constructorParameter) } + override fun addSuperinterface(superinterface: TypeName, delegate: CodeBlock) = builder { this.addSuperinterface(superinterface, delegate) } + override fun addType(typeSpec: TypeSpecSupplier) = builder { this.addType(typeSpec.get()) } + override fun addTag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } + override fun builder(block: TypeSpecBuilderReceiver) = apply { delegate.builder.block() } + // } @ExperimentalKotlinPoetApi diff --git a/kotlin-code-generation/src/main/kotlin/builder/KotlinEnumClassSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/builder/KotlinEnumClassSpecBuilder.kt index 8193eaa..909e32f 100644 --- a/kotlin-code-generation/src/main/kotlin/builder/KotlinEnumClassSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/builder/KotlinEnumClassSpecBuilder.kt @@ -28,7 +28,14 @@ class KotlinEnumClassSpecBuilder internal constructor( KotlinTypeSpecHolderBuilder { companion object { + /** + * Creates new builder. + */ fun builder(name: String): KotlinEnumClassSpecBuilder = builder(simpleClassName(name)) + + /** + * Creates new builder. + */ fun builder(className: ClassName): KotlinEnumClassSpecBuilder = KotlinEnumClassSpecBuilder(className) } @@ -36,30 +43,30 @@ class KotlinEnumClassSpecBuilder internal constructor( delegate.addModifiers(KModifier.ENUM) } - override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec.get()) } - override fun contextReceivers(vararg receiverTypes: TypeName) = builder { this.contextReceivers(*receiverTypes) } - override fun addFunction(funSpec: KotlinFunSpecSupplier) = apply { delegate.addFunction(funSpec.get()) } - override fun addKdoc(kdoc: KDoc) = apply { delegate.addKdoc(kdoc.get()) } - override fun addModifiers(vararg modifiers: KModifier) = builder { this.addModifiers(*modifiers) } - override fun addProperty(propertySpec: KotlinPropertySpecSupplier) = apply { delegate.addProperty(propertySpec.get()) } - override fun addType(typeSpec: TypeSpecSupplier) = builder { this.addType(typeSpec.get()) } - override fun tag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } - fun addEnumConstant(name: String): KotlinEnumClassSpecBuilder = apply { delegate.addEnumConstant(name) } fun addEnumConstant(name: String, typeSpec: TypeSpec = TypeSpec.anonymousClassBuilder().build()): KotlinEnumClassSpecBuilder = builder { this.addEnumConstant(name, typeSpec) } - fun addOriginatingElement(originatingElement: Element): KotlinEnumClassSpecBuilder = builder { this.addOriginatingElement(originatingElement) } + internal fun addOriginatingElement(originatingElement: Element): KotlinEnumClassSpecBuilder = builder { this.addOriginatingElement(originatingElement) } fun addTypeVariable(typeVariable: TypeVariableName): KotlinEnumClassSpecBuilder = builder { this.addTypeVariable(typeVariable) } fun primaryConstructor(primaryConstructor: FunSpecSupplier?): KotlinEnumClassSpecBuilder = builder { this.primaryConstructor(primaryConstructor?.get()) } + fun addInitializerBlock(block: CodeBlock): KotlinEnumClassSpecBuilder = builder { this.addInitializerBlock(block) } + + override fun build(): KotlinEnumClassSpec = KotlinEnumClassSpec(className, delegate.build()) + // + override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec.get()) } + override fun contextReceivers(vararg receiverTypes: TypeName) = builder { this.contextReceivers(*receiverTypes) } + override fun addFunction(funSpec: KotlinFunSpecSupplier) = apply { delegate.addFunction(funSpec.get()) } + override fun addKdoc(kdoc: KDoc) = apply { delegate.addKdoc(kdoc.get()) } + override fun addModifiers(vararg modifiers: KModifier) = builder { this.addModifiers(*modifiers) } + override fun addProperty(propertySpec: KotlinPropertySpecSupplier) = apply { delegate.addProperty(propertySpec.get()) } override fun addSuperinterface(superinterface: TypeName, constructorParameter: String) = builder { this.addSuperinterface(superinterface, constructorParameter) } override fun addSuperinterface(superinterface: TypeName, delegate: CodeBlock) = builder { this.addSuperinterface(superinterface, delegate) } - - fun addInitializerBlock(block: CodeBlock): KotlinEnumClassSpecBuilder = builder { this.addInitializerBlock(block) } - + override fun addType(typeSpec: TypeSpecSupplier) = builder { this.addType(typeSpec.get()) } + override fun addTag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } override fun builder(block: TypeSpecBuilderReceiver): KotlinEnumClassSpecBuilder = apply { delegate.builder.block() } - override fun build(): KotlinEnumClassSpec = KotlinEnumClassSpec(className, delegate.build()) + // } @ExperimentalKotlinPoetApi diff --git a/kotlin-code-generation/src/main/kotlin/builder/KotlinFileSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/builder/KotlinFileSpecBuilder.kt index dcce5df..6bfbc1a 100644 --- a/kotlin-code-generation/src/main/kotlin/builder/KotlinFileSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/builder/KotlinFileSpecBuilder.kt @@ -4,8 +4,11 @@ package io.toolisticon.kotlin.generation.builder import com.squareup.kotlinpoet.* import io.toolisticon.kotlin.generation.BuilderSupplier -import io.toolisticon.kotlin.generation.poet.* +import io.toolisticon.kotlin.generation.poet.FileSpecBuilder import io.toolisticon.kotlin.generation.poet.FileSpecBuilder.Companion.wrap +import io.toolisticon.kotlin.generation.poet.FileSpecBuilderReceiver +import io.toolisticon.kotlin.generation.poet.TypeAliasSpecSupplier +import io.toolisticon.kotlin.generation.poet.TypeSpecSupplier import io.toolisticon.kotlin.generation.spec.* import io.toolisticon.kotlin.generation.support.SUPPRESS_UNUSED import kotlin.reflect.KClass @@ -21,34 +24,46 @@ class KotlinFileSpecBuilder internal constructor( KotlinMemberSpecHolderBuilder, KotlinTypeSpecHolderBuilder { companion object { + /** + * Creates new builder. + */ fun builder(className: ClassName): KotlinFileSpecBuilder { require(className.packageName.isNotEmpty()) { "cannot build file for empty package." } return KotlinFileSpecBuilder(delegate = FileSpecBuilder.builder(className)) } + /** + * Creates new builder. + */ fun builder(memberName: MemberName): KotlinFileSpecBuilder = KotlinFileSpecBuilder( delegate = FileSpecBuilder.builder(memberName) ) + /** + * Creates new builder. + */ fun builder(packageName: String, fileName: String): KotlinFileSpecBuilder = KotlinFileSpecBuilder( delegate = FileSpecBuilder.builder(packageName, fileName) ) + /** + * Creates new builder. + */ fun scriptBuilder(fileName: String, packageName: String = ""): KotlinFileSpecBuilder = KotlinFileSpecBuilder( delegate = FileSpecBuilder.scriptBuilder(fileName, packageName) ) + /** + * Creates new builder. + */ fun builder(spec: KotlinFileSpec) = builder(spec.get()) + /** + * Creates new builder. + */ fun builder(spec: FileSpec) = KotlinFileSpecBuilder(delegate = spec.toBuilder().wrap()) } - override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec.get()) } - override fun addFunction(funSpec: KotlinFunSpecSupplier) = apply { delegate.addFunction(funSpec.get()) } - override fun addProperty(propertySpec: KotlinPropertySpecSupplier) = apply { delegate.addProperty(propertySpec.get()) } - override fun addType(typeSpec: TypeSpecSupplier) = builder { this.addType(typeSpec.get()) } - override fun tag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } - fun addAliasedImport(kclass: KClass<*>, alias: String) = builder { this.addAliasedImport(kclass, alias) } fun addAliasedImport(className: ClassName, alias: String) = builder { this.addAliasedImport(className, alias) } fun addAliasedImport(className: ClassName, memberName: String, alias: String) = builder { this.addAliasedImport(className, memberName, alias) } @@ -74,19 +89,22 @@ class KotlinFileSpecBuilder internal constructor( fun nextControlFlow(controlFlow: String, vararg args: Any) = builder { this.nextControlFlow(controlFlow, *args) } fun endControlFlow() = builder { this.endControlFlow() } - override fun builder(block: FileSpecBuilderReceiver) = apply { - delegate.builder.block() - } - override fun build(): KotlinFileSpec { val spec = delegate.build() return KotlinFileSpec(spec = spec) } - override fun spec(): KotlinFileSpec = build() - override fun get(): FileSpec = build().get() - + // override val className: ClassName = delegate.className + override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec.get()) } + override fun addFunction(funSpec: KotlinFunSpecSupplier) = apply { delegate.addFunction(funSpec.get()) } + override fun addProperty(propertySpec: KotlinPropertySpecSupplier) = apply { delegate.addProperty(propertySpec.get()) } + override fun addType(typeSpec: TypeSpecSupplier) = builder { this.addType(typeSpec.get()) } + override fun addTag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } + override fun builder(block: FileSpecBuilderReceiver) = apply { delegate.builder.block() } + override fun get(): FileSpec = build().get() + override fun spec(): KotlinFileSpec = build() + // } @ExperimentalKotlinPoetApi diff --git a/kotlin-code-generation/src/main/kotlin/builder/KotlinFunSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/builder/KotlinFunSpecBuilder.kt index b8ab8eb..9124a99 100644 --- a/kotlin-code-generation/src/main/kotlin/builder/KotlinFunSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/builder/KotlinFunSpecBuilder.kt @@ -27,40 +27,55 @@ class KotlinFunSpecBuilder internal constructor( KotlinFunSpecSupplier { companion object { + /** + * Creates new builder. + */ fun builder(name: String): KotlinFunSpecBuilder = KotlinFunSpecBuilder( delegate = FunSpecBuilder.builder(name) ) + /** + * Creates new builder. + */ fun builder(memberName: MemberName): KotlinFunSpecBuilder = KotlinFunSpecBuilder( delegate = FunSpecBuilder.builder(memberName) ) + /** + * Creates new builder. + */ fun constructorBuilder(): KotlinFunSpecBuilder = KotlinFunSpecBuilder( delegate = FunSpecBuilder.constructorBuilder() ) + /** + * Creates new builder. + */ fun getterBuilder(): KotlinFunSpecBuilder = KotlinFunSpecBuilder( delegate = FunSpecBuilder.getterBuilder() ) + /** + * Creates new builder. + */ fun setterBuilder(): KotlinFunSpecBuilder = KotlinFunSpecBuilder( delegate = FunSpecBuilder.setterBuilder() ) + /** + * Creates new builder. + */ fun builder(spec: KotlinFunSpec) = builder(spec.get()) + /** + * Creates new builder. + */ fun builder(spec: FunSpec) = KotlinFunSpecBuilder(delegate = spec.toBuilder().wrap()) } fun addParameter(parameter: KotlinParameterSpecSupplier) = builder { this.addParameter(parameter.get()) } - override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec.get()) } - override fun contextReceivers(vararg receiverTypes: TypeName) = builder { this.contextReceivers(*receiverTypes) } - override fun addKdoc(kdoc: KDoc) = apply { delegate.addKdoc(kdoc.get()) } - override fun addModifiers(vararg modifiers: KModifier) = builder { this.addModifiers(*modifiers) } - override fun tag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } - - fun addOriginatingElement(originatingElement: Element) = builder { this.addOriginatingElement(originatingElement) } + internal fun addOriginatingElement(originatingElement: Element) = builder { this.addOriginatingElement(originatingElement) } fun jvmModifiers(modifiers: Iterable) = builder { this.jvmModifiers(modifiers) } fun addTypeVariables(typeVariables: Iterable) = builder { this.addTypeVariables(typeVariables) } fun addTypeVariable(typeVariable: TypeVariableName) = builder { this.addTypeVariable(typeVariable) } @@ -106,10 +121,18 @@ class KotlinFunSpecBuilder internal constructor( fun endControlFlow() = builder { this.endControlFlow() } fun addStatement(format: String, vararg args: Any) = builder { this.addStatement(format, *args) } - override fun builder(block: FunSpecBuilderReceiver): KotlinFunSpecBuilder = apply { delegate.builder.block() } override fun build(): KotlinFunSpec = KotlinFunSpec(spec = delegate.build()) - override fun spec(): KotlinFunSpec = build() + + // + override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec.get()) } + override fun contextReceivers(vararg receiverTypes: TypeName) = builder { this.contextReceivers(*receiverTypes) } + override fun addKdoc(kdoc: KDoc) = apply { delegate.addKdoc(kdoc.get()) } + override fun addModifiers(vararg modifiers: KModifier) = builder { this.addModifiers(*modifiers) } + override fun addTag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } + override fun builder(block: FunSpecBuilderReceiver): KotlinFunSpecBuilder = apply { delegate.builder.block() } override fun get(): FunSpec = build().get() + override fun spec(): KotlinFunSpec = build() + // } @ExperimentalKotlinPoetApi diff --git a/kotlin-code-generation/src/main/kotlin/builder/KotlinInterfaceSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/builder/KotlinInterfaceSpecBuilder.kt index 47c8236..8dcb9f5 100644 --- a/kotlin-code-generation/src/main/kotlin/builder/KotlinInterfaceSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/builder/KotlinInterfaceSpecBuilder.kt @@ -28,7 +28,15 @@ class KotlinInterfaceSpecBuilder internal constructor( KotlinTypeSpecHolderBuilder { companion object { private const val DEFAULT_IS_FUNCTIONAL = false + + /** + * Creates new builder. + */ fun builder(name: String, isFunctionInterface: Boolean = DEFAULT_IS_FUNCTIONAL): KotlinInterfaceSpecBuilder = builder(simpleClassName(name), isFunctionInterface) + + /** + * Creates new builder. + */ fun builder(className: ClassName, isFunctionInterface: Boolean = DEFAULT_IS_FUNCTIONAL): KotlinInterfaceSpecBuilder = KotlinInterfaceSpecBuilder(className, isFunctionInterface) } @@ -37,6 +45,14 @@ class KotlinInterfaceSpecBuilder internal constructor( delegate = if (funInterface) TypeSpecBuilder.funInterfaceBuilder(className) else TypeSpecBuilder.interfaceBuilder(className) ) + internal fun addOriginatingElement(originatingElement: Element) = builder { this.addOriginatingElement(originatingElement) } + fun addTypeVariable(typeVariable: TypeVariableName) = builder { this.addTypeVariable(typeVariable) } + + fun addInitializerBlock(block: CodeBlock) = builder { this.addInitializerBlock(block) } + + override fun build(): KotlinInterfaceSpec = KotlinInterfaceSpec(className = className, spec = delegate.build()) + + // override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec.get()) } override fun contextReceivers(vararg receiverTypes: TypeName) = builder { this.contextReceivers(*receiverTypes) } override fun addFunction(funSpec: KotlinFunSpecSupplier) = apply { delegate.addFunction(funSpec.get()) } @@ -44,18 +60,11 @@ class KotlinInterfaceSpecBuilder internal constructor( override fun addModifiers(vararg modifiers: KModifier) = builder { this.addModifiers(*modifiers) } override fun addProperty(propertySpec: KotlinPropertySpecSupplier) = apply { delegate.addProperty(propertySpec.get()) } override fun addType(typeSpec: TypeSpecSupplier) = builder { this.addType(typeSpec.get()) } - override fun tag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } - - fun addOriginatingElement(originatingElement: Element) = builder { this.addOriginatingElement(originatingElement) } - fun addTypeVariable(typeVariable: TypeVariableName) = builder { this.addTypeVariable(typeVariable) } - override fun addSuperinterface(superinterface: TypeName, constructorParameter: String) = builder { this.addSuperinterface(superinterface, constructorParameter) } override fun addSuperinterface(superinterface: TypeName, delegate: CodeBlock) = builder { this.addSuperinterface(superinterface, delegate) } - - fun addInitializerBlock(block: CodeBlock) = builder { this.addInitializerBlock(block) } - + override fun addTag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } override fun builder(block: TypeSpecBuilderReceiver) = apply { delegate.builder.block() } - override fun build(): KotlinInterfaceSpec = KotlinInterfaceSpec(className = className, spec = delegate.build()) + // } @ExperimentalKotlinPoetApi diff --git a/kotlin-code-generation/src/main/kotlin/builder/KotlinObjectSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/builder/KotlinObjectSpecBuilder.kt index f8d6d74..a6542b4 100644 --- a/kotlin-code-generation/src/main/kotlin/builder/KotlinObjectSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/builder/KotlinObjectSpecBuilder.kt @@ -27,38 +27,42 @@ class KotlinObjectSpecBuilder internal constructor( KotlinSuperInterfaceSupport, KotlinTypeSpecHolderBuilder { companion object { + + /** + * Creates new builder. + */ fun builder(name: String): KotlinObjectSpecBuilder = builder(simpleClassName(name)) + + /** + * Creates new builder. + */ fun builder(className: ClassName): KotlinObjectSpecBuilder = KotlinObjectSpecBuilder(className = className) } internal constructor(className: ClassName) : this(className, TypeSpecBuilder.objectBuilder(className)) + internal fun addOriginatingElement(originatingElement: Element) = builder { this.addOriginatingElement(originatingElement) } + + fun addTypeVariable(typeVariable: TypeVariableName) = builder { this.addTypeVariable(typeVariable) } + fun primaryConstructor(primaryConstructor: FunSpecSupplier?) = builder { this.primaryConstructor(primaryConstructor?.get()) } + + fun addInitializerBlock(block: CodeBlock) = builder { this.addInitializerBlock(block) } + + override fun build(): KotlinObjectSpec = KotlinObjectSpec(className = className, spec = delegate.build()) + + // override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec.get()) } override fun contextReceivers(vararg receiverTypes: TypeName) = builder { this.contextReceivers(*receiverTypes) } override fun addFunction(funSpec: KotlinFunSpecSupplier) = apply { delegate.addFunction(funSpec.get()) } override fun addKdoc(kdoc: KDoc) = apply { delegate.addKdoc(kdoc.get()) } override fun addModifiers(vararg modifiers: KModifier) = builder { this.addModifiers(*modifiers) } override fun addProperty(propertySpec: KotlinPropertySpecSupplier) = apply { delegate.addProperty(propertySpec.get()) } - override fun addType(typeSpec: TypeSpecSupplier) = builder { this.addType(typeSpec.get()) } - override fun tag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } - - fun addOriginatingElement(originatingElement: Element) = builder { this.addOriginatingElement(originatingElement) } - - fun addTypeVariable(typeVariable: TypeVariableName) = builder { this.addTypeVariable(typeVariable) } - fun primaryConstructor(primaryConstructor: FunSpecSupplier?) = builder { this.primaryConstructor(primaryConstructor?.get()) } - fun superclass(superclass: TypeName) = builder { this.superclass(superclass) } - fun superclass(superclass: KClass<*>) = builder { this.superclass(superclass) } - - fun addSuperclassConstructorParameter(format: String, vararg args: Any) = builder { this.addSuperclassConstructorParameter(format, *args) } - fun addSuperclassConstructorParameter(codeBlock: CodeBlock) = builder { this.addSuperclassConstructorParameter(codeBlock) } - override fun addSuperinterface(superinterface: TypeName, constructorParameter: String) = builder { this.addSuperinterface(superinterface, constructorParameter) } override fun addSuperinterface(superinterface: TypeName, delegate: CodeBlock) = builder { this.addSuperinterface(superinterface, delegate) } - - fun addInitializerBlock(block: CodeBlock) = builder { this.addInitializerBlock(block) } - + override fun addType(typeSpec: TypeSpecSupplier) = builder { this.addType(typeSpec.get()) } + override fun addTag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } override fun builder(block: TypeSpecBuilderReceiver): KotlinObjectSpecBuilder = apply { delegate.builder.block() } - override fun build(): KotlinObjectSpec = KotlinObjectSpec(className = className, spec = delegate.build()) + // } @ExperimentalKotlinPoetApi diff --git a/kotlin-code-generation/src/main/kotlin/builder/KotlinParameterSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/builder/KotlinParameterSpecBuilder.kt index 52e0513..c0bbed1 100644 --- a/kotlin-code-generation/src/main/kotlin/builder/KotlinParameterSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/builder/KotlinParameterSpecBuilder.kt @@ -25,45 +25,71 @@ class KotlinParameterSpecBuilder internal constructor( companion object { + /** + * Creates new builder. + */ fun builder(name: String, type: TypeName, vararg modifiers: KModifier): KotlinParameterSpecBuilder = KotlinParameterSpecBuilder( delegate = ParameterSpecBuilder.builder(name, type, *modifiers) ) + /** + * Creates new builder. + */ fun builder(name: String, type: Type, vararg modifiers: KModifier): KotlinParameterSpecBuilder = builder(name, type.asTypeName(), *modifiers) + /** + * Creates new builder. + */ fun builder(name: String, type: KClass<*>, vararg modifiers: KModifier): KotlinParameterSpecBuilder = KotlinParameterSpecBuilder( delegate = ParameterSpecBuilder.builder(name, type.asTypeName(), *modifiers) ) + /** + * Creates new builder. + */ fun builder(name: String, type: TypeName, modifiers: Iterable): KotlinParameterSpecBuilder = KotlinParameterSpecBuilder( delegate = ParameterSpecBuilder.builder(name, type, modifiers) ) + /** + * Creates new builder. + */ fun builder(name: String, type: Type, modifiers: Iterable): KotlinParameterSpecBuilder = KotlinParameterSpecBuilder( delegate = ParameterSpecBuilder.builder(name, type.asTypeName(), modifiers) ) + /** + * Creates new builder. + */ fun builder(name: String, type: KClass<*>, modifiers: Iterable): KotlinParameterSpecBuilder = KotlinParameterSpecBuilder( delegate = ParameterSpecBuilder.builder(name, type.asTypeName(), modifiers) ) + /** + * Creates new builder. + */ fun builder(spec: KotlinParameterSpec) = builder(spec.get()) + /** + * Creates new builder. + */ fun builder(spec: ParameterSpec) = KotlinParameterSpecBuilder(delegate = spec.toBuilder().wrap()) } - override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec.get()) } - override fun addKdoc(kdoc: KDoc) = apply { delegate.addKdoc(kdoc.get()) } - override fun addModifiers(vararg modifiers: KModifier) = builder { this.addModifiers(*modifiers) } - override fun tag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } - fun defaultValue(format: String, vararg args: Any?) = builder { this.defaultValue(format, *args) } fun defaultValue(codeBlock: CodeBlock?) = builder { this.defaultValue(codeBlock) } - override fun builder(block: ParameterSpecBuilderReceiver) = apply { delegate.builder.block() } override fun build(): KotlinParameterSpec = KotlinParameterSpec(spec = delegate.build()) - override fun spec(): KotlinParameterSpec = build() + + // + override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec.get()) } + override fun addKdoc(kdoc: KDoc) = apply { delegate.addKdoc(kdoc.get()) } + override fun addModifiers(vararg modifiers: KModifier) = builder { this.addModifiers(*modifiers) } + override fun addTag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } + override fun builder(block: ParameterSpecBuilderReceiver) = apply { delegate.builder.block() } override fun get(): ParameterSpec = build().get() + override fun spec(): KotlinParameterSpec = build() + // } @ExperimentalKotlinPoetApi diff --git a/kotlin-code-generation/src/main/kotlin/builder/KotlinPropertySpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/builder/KotlinPropertySpecBuilder.kt index 2688086..697faa0 100644 --- a/kotlin-code-generation/src/main/kotlin/builder/KotlinPropertySpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/builder/KotlinPropertySpecBuilder.kt @@ -26,38 +26,54 @@ class KotlinPropertySpecBuilder internal constructor( companion object { + /** + * Creates new builder. + */ fun builder(name: PropertyName, type: TypeName, vararg modifiers: KModifier): KotlinPropertySpecBuilder = KotlinPropertySpecBuilder( delegate = PropertySpecBuilder.builder(name, type, *modifiers) ) + /** + * Creates new builder. + */ fun builder(name: PropertyName, type: Type, vararg modifiers: KModifier): KotlinPropertySpecBuilder = builder( name = name, type = type.asTypeName(), modifiers = modifiers ) + /** + * Creates new builder. + */ fun builder(name: PropertyName, type: KClass<*>, vararg modifiers: KModifier): KotlinPropertySpecBuilder = builder(name, type.asTypeName(), *modifiers) + /** + * Creates new builder. + */ fun builder(name: PropertyName, type: TypeName, modifiers: Iterable): KotlinPropertySpecBuilder = KotlinPropertySpecBuilder( delegate = PropertySpecBuilder.builder(name, type, modifiers) ) + /** + * Creates new builder. + */ fun builder(name: PropertyName, type: KClass<*>, modifiers: Iterable): KotlinPropertySpecBuilder = KotlinPropertySpecBuilder( delegate = PropertySpecBuilder.builder(name, type.asTypeName(), modifiers) ) + /** + * Creates new builder. + */ fun builder(spec: KotlinPropertySpec) = builder(spec.get()) + /** + * Creates new builder. + */ fun builder(spec: PropertySpec) = KotlinPropertySpecBuilder(delegate = spec.toBuilder().wrap()) } - override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec.get()) } - override fun contextReceivers(vararg receiverTypes: TypeName) = builder { this.contextReceivers(*receiverTypes) } - override fun addKdoc(kdoc: KDoc): KotlinPropertySpecBuilder = apply { delegate.addKdoc(kdoc.get()) } - override fun addModifiers(vararg modifiers: KModifier) = builder { this.addModifiers(*modifiers) } - override fun tag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } - fun addOriginatingElement(originatingElement: Element) = builder { this.addOriginatingElement(originatingElement) } + internal fun addOriginatingElement(originatingElement: Element) = builder { this.addOriginatingElement(originatingElement) } fun mutable(mutable: Boolean = true) = builder { this.mutable(mutable) } @@ -72,10 +88,18 @@ class KotlinPropertySpecBuilder internal constructor( fun receiver(receiverType: TypeName?) = builder { this.receiver(receiverType) } fun receiver(receiverType: KClass<*>) = builder { this.receiver(receiverType) } - override fun builder(block: PropertySpecBuilderReceiver) = apply { delegate.builder.block() } override fun build(): KotlinPropertySpec = KotlinPropertySpec(spec = delegate.build()) - override fun spec(): KotlinPropertySpec = build() + + // + override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec.get()) } + override fun contextReceivers(vararg receiverTypes: TypeName) = builder { this.contextReceivers(*receiverTypes) } + override fun addKdoc(kdoc: KDoc): KotlinPropertySpecBuilder = apply { delegate.addKdoc(kdoc.get()) } + override fun addModifiers(vararg modifiers: KModifier) = builder { this.addModifiers(*modifiers) } + override fun addTag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } + override fun builder(block: PropertySpecBuilderReceiver) = apply { delegate.builder.block() } override fun get(): PropertySpec = build().get() + override fun spec(): KotlinPropertySpec = build() + // } @ExperimentalKotlinPoetApi diff --git a/kotlin-code-generation/src/main/kotlin/builder/KotlinTypeAliasSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/builder/KotlinTypeAliasSpecBuilder.kt index db32893..51c75dd 100644 --- a/kotlin-code-generation/src/main/kotlin/builder/KotlinTypeAliasSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/builder/KotlinTypeAliasSpecBuilder.kt @@ -22,24 +22,34 @@ class KotlinTypeAliasSpecBuilder internal constructor( KotlinTypeAliasSpecSupplier { companion object { + + /** + * Creates new builder. + */ fun builder(name: String, type: TypeName): KotlinTypeAliasSpecBuilder = KotlinTypeAliasSpecBuilder(name, type) + + /** + * Creates new builder. + */ fun builder(name: String, type: KClass<*>): KotlinTypeAliasSpecBuilder = builder(name, type.asTypeName()) } internal constructor(name: String, type: TypeName) : this(delegate = TypeAliasSpecBuilder.builder(name, type)) - override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec.get()) } - override fun addKdoc(kdoc: KDoc) = apply { delegate.addKdoc(kdoc.get()) } - override fun addModifiers(vararg modifiers: KModifier) = builder { this.addModifiers(*modifiers) } fun addTypeVariables(typeVariables: Iterable) = builder { this.addTypeVariables(typeVariables) } fun addTypeVariable(typeVariable: TypeVariableName) = builder { this.addTypeVariable(typeVariable) } - override fun tag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } - override fun builder(block: TypeAliasSpecBuilderReceiver) = apply { delegate.builder.block() } override fun build() = KotlinTypeAliasSpec(spec = delegate.build()) - override fun spec(): KotlinTypeAliasSpec = build() - override fun get(): TypeAliasSpec = build().get() + // + override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec.get()) } + override fun addKdoc(kdoc: KDoc) = apply { delegate.addKdoc(kdoc.get()) } + override fun addModifiers(vararg modifiers: KModifier) = builder { this.addModifiers(*modifiers) } + override fun addTag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } + override fun builder(block: TypeAliasSpecBuilderReceiver) = apply { delegate.builder.block() } + override fun get(): TypeAliasSpec = build().get() + override fun spec(): KotlinTypeAliasSpec = build() + // } @ExperimentalKotlinPoetApi diff --git a/kotlin-code-generation/src/main/kotlin/builder/KotlinValueClassSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/builder/KotlinValueClassSpecBuilder.kt index 1bdab00..78bf92e 100644 --- a/kotlin-code-generation/src/main/kotlin/builder/KotlinValueClassSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/builder/KotlinValueClassSpecBuilder.kt @@ -5,7 +5,11 @@ package io.toolisticon.kotlin.generation.builder import com.squareup.kotlinpoet.* import com.squareup.kotlinpoet.jvm.jvmInline import io.toolisticon.kotlin.generation.KotlinCodeGeneration.simpleClassName -import io.toolisticon.kotlin.generation.poet.* +import io.toolisticon.kotlin.generation.builder.KotlinFunSpecBuilder.Companion.constructorBuilder +import io.toolisticon.kotlin.generation.poet.KDoc +import io.toolisticon.kotlin.generation.poet.TypeSpecBuilder +import io.toolisticon.kotlin.generation.poet.TypeSpecBuilderReceiver +import io.toolisticon.kotlin.generation.poet.TypeSpecSupplier import io.toolisticon.kotlin.generation.spec.* import io.toolisticon.kotlin.generation.support.SUPPRESS_UNUSED import javax.lang.model.element.Element @@ -17,7 +21,7 @@ import kotlin.reflect.KClass @ExperimentalKotlinPoetApi class KotlinValueClassSpecBuilder internal constructor( val className: ClassName, - private val delegate: TypeSpecBuilder + internal val delegate: TypeSpecBuilder ) : KotlinGeneratorTypeSpecBuilder, KotlinAnnotatableDocumentableModifiableBuilder, KotlinConstructorPropertySupport, @@ -27,49 +31,64 @@ class KotlinValueClassSpecBuilder internal constructor( KotlinTypeSpecHolderBuilder { companion object { + + /** + * Creates new builder. + */ fun builder(name: String): KotlinValueClassSpecBuilder = builder(simpleClassName(name)) + + /** + * Creates new builder. + */ fun builder(className: ClassName): KotlinValueClassSpecBuilder = KotlinValueClassSpecBuilder(className) } - lateinit var constructorProperty: KotlinConstructorPropertySpecSupplier + internal lateinit var constructorProperty: KotlinConstructorPropertySpecSupplier internal constructor(className: ClassName) : this(className = className, delegate = TypeSpecBuilder.classBuilder(className)) { delegate.addModifiers(KModifier.VALUE) delegate.builder.jvmInline() } - override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec.get()) } - override fun addConstructorProperty(spec: KotlinConstructorPropertySpecSupplier) = apply { this.constructorProperty = spec } - override fun contextReceivers(vararg receiverTypes: TypeName) = builder { this.contextReceivers(*receiverTypes) } - override fun addFunction(funSpec: KotlinFunSpecSupplier) = apply { delegate.addFunction(funSpec.get()) } - override fun addKdoc(kdoc: KDoc) = apply { delegate.addKdoc(kdoc.get()) } - override fun addModifiers(vararg modifiers: KModifier) = builder { this.addModifiers(*modifiers) } - override fun addProperty(propertySpec: KotlinPropertySpecSupplier) = apply { delegate.addProperty(propertySpec.get()) } - override fun addType(typeSpec: TypeSpecSupplier) = builder { this.addType(typeSpec.get()) } - override fun tag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } - - fun addOriginatingElement(originatingElement: Element) = builder { this.addOriginatingElement(originatingElement) } + internal fun addOriginatingElement(originatingElement: Element) = builder { this.addOriginatingElement(originatingElement) } fun addTypeVariable(typeVariable: TypeVariableName) = builder { this.addTypeVariable(typeVariable) } - override fun addSuperinterface(superinterface: TypeName, constructorParameter: String) = builder { this.addSuperinterface(superinterface, constructorParameter) } - override fun addSuperinterface(superinterface: TypeName, delegate: CodeBlock) = builder { this.addSuperinterface(superinterface, delegate) } - fun addInitializerBlock(block: CodeBlock) = builder { this.addInitializerBlock(block) } - override fun builder(block: TypeSpecBuilderReceiver) = apply { delegate.builder.block() } + override fun build(): KotlinValueClassSpec = build { } - override fun build(): KotlinValueClassSpec { + /** + * Use internally when creating extra builders that re-use this builder. + */ + internal fun build(block: KotlinValueClassSpecBuilderReceiver): KotlinValueClassSpec { check(::constructorProperty.isInitialized) { "Value class must have exactly one property." } - val constructor = KotlinFunSpecBuilder.constructorBuilder() + val constructor = constructorBuilder() .addParameter(this.constructorProperty.spec().parameter) .build() delegate.addProperty(constructorProperty.spec().property.get()) delegate.builder.primaryConstructor(constructor.get()) + this.block() + return KotlinValueClassSpec(className = className, spec = delegate.build()) } + + // + override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec.get()) } + override fun addConstructorProperty(spec: KotlinConstructorPropertySpecSupplier) = apply { this.constructorProperty = spec } + override fun contextReceivers(vararg receiverTypes: TypeName) = builder { this.contextReceivers(*receiverTypes) } + override fun addFunction(funSpec: KotlinFunSpecSupplier) = apply { delegate.addFunction(funSpec.get()) } + override fun addKdoc(kdoc: KDoc) = apply { delegate.addKdoc(kdoc.get()) } + override fun addModifiers(vararg modifiers: KModifier) = builder { this.addModifiers(*modifiers) } + override fun addProperty(propertySpec: KotlinPropertySpecSupplier) = apply { delegate.addProperty(propertySpec.get()) } + override fun addSuperinterface(superinterface: TypeName, constructorParameter: String) = builder { this.addSuperinterface(superinterface, constructorParameter) } + override fun addSuperinterface(superinterface: TypeName, delegate: CodeBlock) = builder { this.addSuperinterface(superinterface, delegate) } + override fun addType(typeSpec: TypeSpecSupplier) = builder { this.addType(typeSpec.get()) } + override fun addTag(type: KClass<*>, tag: Any?) = builder { this.tag(type, tag) } + override fun builder(block: TypeSpecBuilderReceiver) = apply { delegate.builder.block() } + // } @ExperimentalKotlinPoetApi diff --git a/kotlin-code-generation/src/main/kotlin/builder/_types.kt b/kotlin-code-generation/src/main/kotlin/builder/_types.kt index be17722..6b5f369 100644 --- a/kotlin-code-generation/src/main/kotlin/builder/_types.kt +++ b/kotlin-code-generation/src/main/kotlin/builder/_types.kt @@ -47,7 +47,7 @@ interface KotlinGeneratorTypeSpecBuilder : KotlinTaggableBuilder { +interface KotlinConstructorPropertySupport : KotlinTaggableBuilder { /** * Implementing builder needs to store the spec provided and apply it to the build. @@ -263,14 +263,14 @@ sealed interface KotlinTaggableBuilder { /** * @see com.squareup.kotlinpoet.Taggable#Builder#tag */ - fun tag(type: KClass<*>, tag: Any?): SELF + fun addTag(type: KClass<*>, tag: Any?): SELF /** * Store tag under key of ::class. */ - fun tag(tag: T): SELF = tag(tag::class, tag) + fun addTag(tag: T): SELF = addTag(tag::class, tag) - fun removeTag(type: KClass<*>): SELF = tag(type, null) + fun removeTag(type: KClass<*>): SELF = addTag(type, null) } /** diff --git a/kotlin-code-generation/src/main/kotlin/builder/extra/DelegateListValueClassSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/builder/extra/DelegateListValueClassSpecBuilder.kt new file mode 100644 index 0000000..d844d04 --- /dev/null +++ b/kotlin-code-generation/src/main/kotlin/builder/extra/DelegateListValueClassSpecBuilder.kt @@ -0,0 +1,85 @@ +package io.toolisticon.kotlin.generation.builder.extra + +import com.squareup.kotlinpoet.* +import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy +import io.toolisticon.kotlin.generation.KotlinCodeGeneration.simpleClassName +import io.toolisticon.kotlin.generation.SimpleName +import io.toolisticon.kotlin.generation.builder.KotlinAnnotatableDocumentableModifiableBuilder +import io.toolisticon.kotlin.generation.builder.KotlinGeneratorTypeSpecBuilder +import io.toolisticon.kotlin.generation.builder.KotlinSuperInterfaceSupport +import io.toolisticon.kotlin.generation.builder.KotlinValueClassSpecBuilder +import io.toolisticon.kotlin.generation.poet.KDoc +import io.toolisticon.kotlin.generation.spec.ClassSpecType +import io.toolisticon.kotlin.generation.spec.KotlinAnnotationSpecSupplier +import io.toolisticon.kotlin.generation.spec.KotlinValueClassSpec +import kotlin.reflect.KClass + +/** + * Generator that wraps a list holding given elementType in a value class and delegates the list. + */ +@ExperimentalKotlinPoetApi +class DelegateListValueClassSpecBuilder internal constructor( + private val delegate: KotlinValueClassSpecBuilder, + private val elementType: TypeName, +) : KotlinGeneratorTypeSpecBuilder, + KotlinAnnotatableDocumentableModifiableBuilder, + KotlinSuperInterfaceSupport { + + companion object { + /** + * Creates new builder. + */ + fun builder(name: SimpleName, elementType: TypeName) = builder( + className = simpleClassName(name), + elementType = elementType + ) + + /** + * Creates new builder. + */ + fun builder(className: ClassName, elementType: TypeName) = DelegateListValueClassSpecBuilder( + className = className, + elementType = elementType + ) + } + + private var propertyName: String = "delegate" + + internal constructor(className: ClassName, elementType: TypeName) : this( + delegate = KotlinValueClassSpecBuilder(className), + elementType = List::class.asClassName().parameterizedBy(elementType), + ) { + delegate.addTag(ClassSpecType.LIST) + } + + /** + * Modify the default property name. + */ + fun propertyName(propertyName: String) = apply { + require(propertyName.isNotBlank()) { "Property name cannot be blank." } + this.propertyName = propertyName + } + + override fun build(): KotlinValueClassSpec { + delegate.addConstructorProperty(propertyName, elementType) { + makePrivate() + } + val constructorProperty = delegate.constructorProperty + return delegate.build { + addSuperinterface(elementType, constructorProperty.name) + } + } + + // + override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec) } + override fun addKdoc(kdoc: KDoc) = apply { delegate.addKdoc(kdoc) } + override fun addModifiers(vararg modifiers: KModifier) = apply { delegate.addModifiers(*modifiers) } + override fun addSuperinterface(superinterface: TypeName, constructorParameter: String) = apply { delegate.addSuperinterface(superinterface, constructorParameter) } + override fun addSuperinterface(superinterface: TypeName, delegate: CodeBlock) = apply { this.delegate.addSuperinterface(superinterface, delegate) } + override fun addTag(type: KClass<*>, tag: Any?) = apply { delegate.addTag(type, tag) } + override fun builder(block: TypeSpec.Builder.() -> Unit) = apply { delegate.builder(block) } + // +} + +@ExperimentalKotlinPoetApi +typealias DelegateListValueClassSpecBuilderReceiver = DelegateListValueClassSpecBuilder.() -> Unit diff --git a/kotlin-code-generation/src/main/kotlin/builder/extra/DelegateMapValueClassSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/builder/extra/DelegateMapValueClassSpecBuilder.kt new file mode 100644 index 0000000..8e0375f --- /dev/null +++ b/kotlin-code-generation/src/main/kotlin/builder/extra/DelegateMapValueClassSpecBuilder.kt @@ -0,0 +1,85 @@ +package io.toolisticon.kotlin.generation.builder.extra + +import com.squareup.kotlinpoet.* +import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy +import io.toolisticon.kotlin.generation.KotlinCodeGeneration.simpleClassName +import io.toolisticon.kotlin.generation.SimpleName +import io.toolisticon.kotlin.generation.builder.KotlinAnnotatableDocumentableModifiableBuilder +import io.toolisticon.kotlin.generation.builder.KotlinGeneratorTypeSpecBuilder +import io.toolisticon.kotlin.generation.builder.KotlinSuperInterfaceSupport +import io.toolisticon.kotlin.generation.builder.KotlinValueClassSpecBuilder +import io.toolisticon.kotlin.generation.poet.KDoc +import io.toolisticon.kotlin.generation.spec.ClassSpecType +import io.toolisticon.kotlin.generation.spec.KotlinAnnotationSpecSupplier +import io.toolisticon.kotlin.generation.spec.KotlinValueClassSpec +import kotlin.reflect.KClass + +/** + * Generator that wraps a map holding given key/valueType in a value class and delegates the map. + */ +@ExperimentalKotlinPoetApi +class DelegateMapValueClassSpecBuilder internal constructor( + private val delegate: KotlinValueClassSpecBuilder, + private val mapType: TypeName, +) : KotlinGeneratorTypeSpecBuilder, + KotlinAnnotatableDocumentableModifiableBuilder, + KotlinSuperInterfaceSupport { + + companion object { + val DEFAULT_KEY_TYPE = String::class.asTypeName() + + /** + * Creates new builder. + */ + fun builder(name: SimpleName, keyType: TypeName = DEFAULT_KEY_TYPE, valueType: TypeName) = builder(className = simpleClassName(name), keyType = keyType, valueType = valueType) + + /** + * Creates new builder. + */ + fun builder(className: ClassName, keyType: TypeName = DEFAULT_KEY_TYPE, valueType: TypeName) = DelegateMapValueClassSpecBuilder( + className = className, + keyType = keyType, + valueType = valueType + ) + } + + private var propertyName: String = "delegate" + + internal constructor(className: ClassName, keyType: TypeName, valueType: TypeName) : this( + delegate = KotlinValueClassSpecBuilder(className), + mapType = Map::class.asTypeName().parameterizedBy(keyType, valueType) + ) { + delegate.addTag(ClassSpecType.MAP) + } + + /** + * Modify the default property name. + */ + fun propertyName(propertyName: String) = apply { + require(propertyName.isNotBlank()) { "Property name cannot be blank." } + this.propertyName = propertyName + } + + override fun build(): KotlinValueClassSpec { + delegate.addConstructorProperty(propertyName, mapType) { + makePrivate() + } + val constructorProperty = delegate.constructorProperty + return delegate.build { + addSuperinterface(mapType, constructorProperty.name) + } + } + + // + override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec) } + override fun addKdoc(kdoc: KDoc) = apply { delegate.addKdoc(kdoc) } + override fun addModifiers(vararg modifiers: KModifier) = apply { delegate.addModifiers(*modifiers) } + override fun addSuperinterface(superinterface: TypeName, constructorParameter: String) = apply { delegate.addSuperinterface(superinterface, constructorParameter) } + override fun addSuperinterface(superinterface: TypeName, delegate: CodeBlock) = apply { this.delegate.addSuperinterface(superinterface, delegate) } + override fun builder(block: TypeSpec.Builder.() -> Unit) = apply { delegate.builder(block) } + override fun addTag(type: KClass<*>, tag: Any?) = apply { delegate.addTag(type, tag) } + // +} + +@ExperimentalKotlinPoetApi +typealias DelegateMapValueClassSpecBuilderReceiver = DelegateMapValueClassSpecBuilder.() -> Unit diff --git a/kotlin-code-generation/src/main/kotlin/builder/extra/RuntimeExceptionSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/builder/extra/RuntimeExceptionSpecBuilder.kt index 0e78fe0..35a090a 100644 --- a/kotlin-code-generation/src/main/kotlin/builder/extra/RuntimeExceptionSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/builder/extra/RuntimeExceptionSpecBuilder.kt @@ -8,20 +8,16 @@ import com.squareup.kotlinpoet.TypeName import com.squareup.kotlinpoet.TypeSpec import com.squareup.kotlinpoet.asTypeName import io.toolisticon.kotlin.generation.KotlinCodeGeneration.buildParameter -import io.toolisticon.kotlin.generation.KotlinCodeGeneration.builder.constructorBuilder import io.toolisticon.kotlin.generation.KotlinCodeGeneration.format.FORMAT_NAME import io.toolisticon.kotlin.generation.KotlinCodeGeneration.format.FORMAT_STRING_TEMPLATE import io.toolisticon.kotlin.generation.KotlinCodeGeneration.name.nullable import io.toolisticon.kotlin.generation.KotlinCodeGeneration.simpleClassName -import io.toolisticon.kotlin.generation.builder.KotlinAnnotatableDocumentableModifiableBuilder -import io.toolisticon.kotlin.generation.builder.KotlinClassSpecBuilder -import io.toolisticon.kotlin.generation.builder.KotlinFunSpecBuilder -import io.toolisticon.kotlin.generation.builder.KotlinGeneratorTypeSpecBuilder -import io.toolisticon.kotlin.generation.builder.KotlinSuperInterfaceSupport +import io.toolisticon.kotlin.generation.builder.* +import io.toolisticon.kotlin.generation.builder.KotlinConstructorPropertySpecBuilder.Companion.primaryConstructorWithProperties +import io.toolisticon.kotlin.generation.poet.FunSpecBuilder import io.toolisticon.kotlin.generation.poet.KDoc -import io.toolisticon.kotlin.generation.spec.ClassSpecType -import io.toolisticon.kotlin.generation.spec.KotlinAnnotationSpecSupplier -import io.toolisticon.kotlin.generation.spec.KotlinClassSpec +import io.toolisticon.kotlin.generation.spec.* +import io.toolisticon.kotlin.generation.spec.toList import kotlin.reflect.KClass /** @@ -33,12 +29,21 @@ class RuntimeExceptionSpecBuilder internal constructor( private val delegate: KotlinClassSpecBuilder, ) : KotlinGeneratorTypeSpecBuilder, KotlinAnnotatableDocumentableModifiableBuilder, + KotlinConstructorPropertySupport, KotlinSuperInterfaceSupport { + companion object { private val NULLABLE_THROWABLE = Throwable::class.asTypeName().nullable() private val FIND_TEMPLATE_PARAMS = Regex("\\$(\\w+)") + /** + * Creates new builder. + */ fun builder(name: String): RuntimeExceptionSpecBuilder = builder(simpleClassName(name)) + + /** + * Creates new builder. + */ fun builder(className: ClassName): RuntimeExceptionSpecBuilder = RuntimeExceptionSpecBuilder(className = className) /** @@ -53,10 +58,14 @@ class RuntimeExceptionSpecBuilder internal constructor( private val _messageTemplateParameters = LinkedHashMap() internal constructor(className: ClassName) : this(delegate = KotlinClassSpecBuilder(className = className)) { - tag(ClassSpecType.EXCEPTION) + addTag(ClassSpecType.EXCEPTION) delegate.superclass(RuntimeException::class) } + /** + * Sets a string message template. Placeholders `\$foo` are parsed and automatically used + * as parameters of type `Any`, unless explicitly overwritten by `addParameter` or `addConstructorProperty`. + */ fun messageTemplate(messageTemplate: String) = apply { _messageTemplate = messageTemplate @@ -65,12 +74,21 @@ class RuntimeExceptionSpecBuilder internal constructor( } } + /** + * Define the type of a placeholder parameter in the message template. + */ fun addParameter(name: String, type: KClass<*>) = addParameter(name, type.asTypeName()) + /** + * Define the type of a placeholder parameter in the message template. + */ fun addParameter(name: String, type: TypeName) = apply { _messageTemplateParameters[name] = type } + /** + * Include the cause (Throwable) in the constructor. + */ fun includeCause(name: String? = null) = apply { _cause = true to (name ?: _cause.second) } @@ -79,8 +97,16 @@ class RuntimeExceptionSpecBuilder internal constructor( require(::_messageTemplate.isInitialized) { "Message template must be initialized." } delegate.addSuperclassConstructorParameter(FORMAT_STRING_TEMPLATE, _messageTemplate) - val constructorBuilder: KotlinFunSpecBuilder = _messageTemplateParameters.entries.fold(constructorBuilder()) { acc, cur -> - acc.addParameter(cur.key, cur.value) + val constructorProperties = delegate.constructorProperties + + val constructorBuilder: FunSpecBuilder = if (constructorProperties.isNotEmpty()) { + delegate.delegate.primaryConstructorWithProperties(toList(constructorProperties.values)) + } else { + FunSpecBuilder.constructorBuilder() + } + + _messageTemplateParameters.entries.filterNot { constructorProperties.containsKey(it.key) }.forEach { (name, type) -> + constructorBuilder.addParameter(name, type) } if (_cause.first) { @@ -89,23 +115,26 @@ class RuntimeExceptionSpecBuilder internal constructor( defaultValue("null") } - constructorBuilder.addParameter(nullableCauseParameter) + constructorBuilder.addParameter(nullableCauseParameter.get()) } - return delegate.primaryConstructor(constructorBuilder).build() + // TODO bypass classSpecBuild until issue 47 is solved + return KotlinClassSpec( + className = delegate.className, + spec = delegate.delegate + .primaryConstructor(constructorBuilder.build()) + .build() + ) } // override fun addAnnotation(spec: KotlinAnnotationSpecSupplier) = apply { delegate.addAnnotation(spec) } + override fun addConstructorProperty(spec: KotlinConstructorPropertySpecSupplier) = apply { delegate.addConstructorProperty(spec) } override fun addKdoc(kdoc: KDoc) = apply { delegate.addKdoc(kdoc) } override fun addModifiers(vararg modifiers: KModifier) = apply { delegate.addModifiers(*modifiers) } override fun addSuperinterface(superinterface: TypeName, constructorParameter: String) = apply { delegate.addSuperinterface(superinterface, constructorParameter) } - override fun addSuperinterface(superinterface: TypeName, delegate: CodeBlock): RuntimeExceptionSpecBuilder { - TODO("Not yet implemented") - } - - //override fun addSuperinterface(superinterface: TypeName, delegate: CodeBlock) : RuntimeExceptionSpecBuilder= apply { delegate.addS } - override fun tag(type: KClass<*>, tag: Any?) = apply { delegate.tag(type, tag) } + override fun addSuperinterface(superinterface: TypeName, delegate: CodeBlock): RuntimeExceptionSpecBuilder = apply { this.delegate.addSuperinterface(superinterface, delegate) } + override fun addTag(type: KClass<*>, tag: Any?) = apply { delegate.addTag(type, tag) } override fun builder(block: TypeSpec.Builder.() -> Unit): RuntimeExceptionSpecBuilder = apply { delegate.builder(block) } // } diff --git a/kotlin-code-generation/src/main/kotlin/poet/AnnotationSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/poet/AnnotationSpecBuilder.kt index d9deb80..cf2de7c 100644 --- a/kotlin-code-generation/src/main/kotlin/poet/AnnotationSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/poet/AnnotationSpecBuilder.kt @@ -9,14 +9,25 @@ import kotlin.reflect.KClass */ class AnnotationSpecBuilder( override val builder: AnnotationSpec.Builder -) : PoetSpecBuilder, PoetTaggableBuilder { +) : PoetSpecBuilder, + AnnotationSpecSupplier, + PoetTaggableBuilder { companion object { - fun AnnotationSpec.Builder.wrap() = AnnotationSpecBuilder(this) + internal fun AnnotationSpec.Builder.wrap() = AnnotationSpecBuilder(this) + /** + * Creates new builder. + */ fun builder(type: ClassName): AnnotationSpecBuilder = AnnotationSpec.builder(type).wrap() + /** + * Creates new builder. + */ fun builder(type: ParameterizedTypeName): AnnotationSpecBuilder = AnnotationSpec.builder(type).wrap() + /** + * Creates new builder. + */ fun builder(type: KClass): AnnotationSpecBuilder = builder(type.asClassName()) } diff --git a/kotlin-code-generation/src/main/kotlin/poet/FileSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/poet/FileSpecBuilder.kt index abcfa74..7aca34a 100644 --- a/kotlin-code-generation/src/main/kotlin/poet/FileSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/poet/FileSpecBuilder.kt @@ -12,6 +12,7 @@ import kotlin.reflect.KClass class FileSpecBuilder( override val builder: FileSpec.Builder ) : PoetSpecBuilder, + FileSpecSupplier, PoetAnnotatableBuilder, PoetMemberSpecHolderBuilder, PoetTypeSpecHolderBuilder, diff --git a/kotlin-code-generation/src/main/kotlin/poet/FunSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/poet/FunSpecBuilder.kt index 9569ae3..70e431d 100644 --- a/kotlin-code-generation/src/main/kotlin/poet/FunSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/poet/FunSpecBuilder.kt @@ -12,6 +12,7 @@ import kotlin.reflect.KClass class FunSpecBuilder( override val builder: FunSpec.Builder ) : PoetSpecBuilder, + FunSpecSupplier, PoetAnnotatableBuilder, PoetContextReceivableBuilder, PoetDocumentableBuilder, diff --git a/kotlin-code-generation/src/main/kotlin/poet/ParameterSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/poet/ParameterSpecBuilder.kt index 88dd123..01ada1c 100644 --- a/kotlin-code-generation/src/main/kotlin/poet/ParameterSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/poet/ParameterSpecBuilder.kt @@ -10,6 +10,7 @@ import kotlin.reflect.KClass class ParameterSpecBuilder( override val builder: ParameterSpec.Builder ) : PoetSpecBuilder, + ParameterSpecSupplier, PoetAnnotatableBuilder, PoetTaggableBuilder, PoetDocumentableBuilder { diff --git a/kotlin-code-generation/src/main/kotlin/poet/PropertySpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/poet/PropertySpecBuilder.kt index 4c86cca..d6d09d3 100644 --- a/kotlin-code-generation/src/main/kotlin/poet/PropertySpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/poet/PropertySpecBuilder.kt @@ -12,6 +12,7 @@ import kotlin.reflect.KClass class PropertySpecBuilder( override val builder: PropertySpec.Builder ) : PoetSpecBuilder, + PropertySpecSupplier, PoetAnnotatableBuilder, PoetContextReceivableBuilder, PoetTaggableBuilder, diff --git a/kotlin-code-generation/src/main/kotlin/poet/TypeAliasSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/poet/TypeAliasSpecBuilder.kt index 755ef4e..a16d59b 100644 --- a/kotlin-code-generation/src/main/kotlin/poet/TypeAliasSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/poet/TypeAliasSpecBuilder.kt @@ -9,6 +9,7 @@ import kotlin.reflect.KClass class TypeAliasSpecBuilder( override val builder: TypeAliasSpec.Builder ) : PoetSpecBuilder, + TypeAliasSpecSupplier, PoetAnnotatableBuilder, PoetTaggableBuilder, PoetDocumentableBuilder { diff --git a/kotlin-code-generation/src/main/kotlin/poet/TypeSpecBuilder.kt b/kotlin-code-generation/src/main/kotlin/poet/TypeSpecBuilder.kt index 9264495..013c1d4 100644 --- a/kotlin-code-generation/src/main/kotlin/poet/TypeSpecBuilder.kt +++ b/kotlin-code-generation/src/main/kotlin/poet/TypeSpecBuilder.kt @@ -24,6 +24,7 @@ import kotlin.reflect.KClass class TypeSpecBuilder( override val builder: TypeSpec.Builder ) : PoetSpecBuilder, + TypeSpecSupplier, PoetAnnotatableBuilder, PoetContextReceivableBuilder, PoetDocumentableBuilder, diff --git a/kotlin-code-generation/src/test/kotlin/spec/DelegateListValueClassSpecTest.kt b/kotlin-code-generation/src/test/kotlin/spec/DelegateListValueClassSpecTest.kt new file mode 100644 index 0000000..01d1393 --- /dev/null +++ b/kotlin-code-generation/src/test/kotlin/spec/DelegateListValueClassSpecTest.kt @@ -0,0 +1,38 @@ +package io.toolisticon.kotlin.generation.spec + +import com.squareup.kotlinpoet.ExperimentalKotlinPoetApi +import io.toolisticon.kotlin.generation.KotlinCodeGeneration.buildDelegateListValueClass +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +@ExperimentalKotlinPoetApi +internal class DelegateListValueClassSpecTest { + + @Test + fun `create delegate list`() { + + val list = buildDelegateListValueClass( + packageName = "xyz", + simpleName = "MyList", + items = String::class + ) { + propertyName("foo") + }.toFileSpec() + + assertThat(list.code).isEqualTo( + """ + package xyz + + import kotlin.String + import kotlin.collections.List + import kotlin.jvm.JvmInline + + @JvmInline + public value class MyList( + private val foo: List, + ) : List by foo + + """.trimIndent() + ) + } +} diff --git a/kotlin-code-generation/src/test/kotlin/spec/KotlinExceptionClassTest.kt b/kotlin-code-generation/src/test/kotlin/spec/KotlinExceptionClassTest.kt index c987a83..6eb2eeb 100644 --- a/kotlin-code-generation/src/test/kotlin/spec/KotlinExceptionClassTest.kt +++ b/kotlin-code-generation/src/test/kotlin/spec/KotlinExceptionClassTest.kt @@ -13,7 +13,9 @@ class KotlinExceptionClassTest { val exception = KotlinCodeGeneration.buildRuntimeExceptionClass("foo", "DummyException") { addKdoc(" This DummyException indicates something really went wrong. Totally!") messageTemplate("Something bad happened, expected=\$foo but got \$bar.") - addParameter("foo", Int::class) + addConstructorProperty("foo", Int::class) { + makePrivate() + } addParameter("bar", Long::class) includeCause("e") }.toFileSpec() @@ -31,7 +33,7 @@ class KotlinExceptionClassTest { * This DummyException indicates something really went wrong. Totally! */ public class DummyException( - foo: Int, + private val foo: Int, bar: Long, e: Throwable? = null, ) : RuntimeException(""${'"'}Something bad happened, expected=${'$'}foo but got ${'$'}bar.""${'"'}, e)