From 901ebefe08f7f52485611817c7e81d47ec732097 Mon Sep 17 00:00:00 2001 From: Ian Botsford <83236726+ianbotsf@users.noreply.github.com> Date: Wed, 17 Dec 2025 22:39:29 +0000 Subject: [PATCH] Annotate DDB Mapper-generated declarations as @GeneratedApi --- hll/build.gradle.kts | 2 +- .../codegen/operations/model/Structure.kt | 4 +- .../operations/rendering/DataTypeGenerator.kt | 15 ++- .../rendering/OperationsTypeRenderer.kt | 2 +- .../operations/rendering/PaginatorRenderer.kt | 9 +- .../annotations/rendering/SchemaRenderer.kt | 27 +++- .../plugins/SchemaGeneratorPluginTest.kt | 121 +++++++++++++++--- .../dynamodb-mapper/api/dynamodb-mapper.api | 64 --------- .../kotlin/hll/codegen/core/CodeGenerator.kt | 2 +- .../kotlin/hll/codegen/model/HasAttributes.kt | 13 ++ .../sdk/kotlin/hll/codegen/model/HllTypes.kt | 18 +++ .../sdk/kotlin/hll/codegen/model/Member.kt | 14 +- .../hll/codegen/model/ModelAttributes.kt | 16 +++ .../sdk/kotlin/hll/codegen/model/Operation.kt | 14 +- .../sdk/kotlin/hll/codegen/model/Structure.kt | 26 ++-- .../hll/codegen/rendering/BuilderRenderer.kt | 18 ++- .../hll/codegen/rendering/RenderContext.kt | 5 +- .../hll/codegen/util/GeneratedApiUtils.kt | 38 ++++++ 18 files changed, 277 insertions(+), 131 deletions(-) create mode 100644 hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/HasAttributes.kt create mode 100644 hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/HllTypes.kt create mode 100644 hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/util/GeneratedApiUtils.kt diff --git a/hll/build.gradle.kts b/hll/build.gradle.kts index 527cdc40266..d7a068341ab 100644 --- a/hll/build.gradle.kts +++ b/hll/build.gradle.kts @@ -100,11 +100,11 @@ val projectsToIgnore = listOf( "dynamodb-mapper-codegen", "dynamodb-mapper-ops-codegen", "dynamodb-mapper-schema-codegen", - "dynamodb-mapper-schema-generator-plugin-test", ).filter { it in subprojects.map { it.name }.toSet() } // Some projects may not be in the build depending on bootstrapping apiValidation { ignoredProjects += projectsToIgnore + nonPublicMarkers += "aws.smithy.kotlin.runtime.GeneratedApi" } // Configure Dokka for subprojects diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/model/Structure.kt b/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/model/Structure.kt index 98afcc8da8b..dab10c2d73c 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/model/Structure.kt +++ b/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/model/Structure.kt @@ -21,7 +21,9 @@ internal fun Structure.toHighLevel(pkg: String): Structure { val nullable = llMember.type.nullable val hlMember = when (val behavior = llMember.codegenBehavior) { - MemberCodegenBehavior.PassThrough -> llMember + MemberCodegenBehavior.PassThrough -> llMember.copy( + attributes = attributes + (ModelAttributes.GeneratedApi to true), + ) MemberCodegenBehavior.MapAll, MemberCodegenBehavior.MapKeys -> llMember.copy(type = TypeVar("T", nullable)) diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/rendering/DataTypeGenerator.kt b/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/rendering/DataTypeGenerator.kt index f07fe3dc261..534d5551b7e 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/rendering/DataTypeGenerator.kt +++ b/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/rendering/DataTypeGenerator.kt @@ -13,6 +13,7 @@ import aws.sdk.kotlin.hll.codegen.rendering.BuilderRenderer import aws.sdk.kotlin.hll.codegen.rendering.RenderContext import aws.sdk.kotlin.hll.codegen.rendering.RenderOptions import aws.sdk.kotlin.hll.codegen.rendering.Visibility +import aws.sdk.kotlin.hll.codegen.util.generatedAnnotation import aws.sdk.kotlin.hll.codegen.util.plus /** @@ -66,10 +67,15 @@ internal class DataTypeGenerator( private val structure: Structure, ) : CodeGenerator by generator { fun generate() { + generatedAnnotation(structure) withBlock("public interface #T {", "}", structure.type) { + generatedAnnotation(structure) write("public companion object { }") // leave room for future expansion blankLine() - members { write("public val #L: #T", name, type) } + members { + generatedAnnotation(this) + write("public val #L: #T", name, type) + } } blankLine() @@ -85,10 +91,11 @@ internal class DataTypeGenerator( val builderCtx = ctx.copy( attributes = ctx.attributes + (RenderOptions.VisibilityAttribute to Visibility.PUBLIC), ) - val builderName = BuilderRenderer.builderName(structure.type) - BuilderRenderer(this, structure.type, implType, structure.members, builderCtx).render() + val builderName = BuilderRenderer.builderName(structure) + BuilderRenderer(this, structure, implType, structure.members, builderCtx).render() blankLine() + generatedAnnotation(structure) withBlock( "public fun #1L#2T.toBuilder(): #3L#4L = #3L#4L().apply {", "}", @@ -101,6 +108,7 @@ internal class DataTypeGenerator( } blankLine() + generatedAnnotation(structure) withBlock( "public fun #1L#2T.copy(block: #3L#4L.() -> Unit): #2T =", "", @@ -113,6 +121,7 @@ internal class DataTypeGenerator( } blankLine() + generatedAnnotation(structure) withBlock( "public fun #L#L(block: #L#L.() -> Unit): #T =", "", diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/rendering/OperationsTypeRenderer.kt b/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/rendering/OperationsTypeRenderer.kt index 1919cbd5e4e..c1db43212cd 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/rendering/OperationsTypeRenderer.kt +++ b/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/rendering/OperationsTypeRenderer.kt @@ -54,7 +54,7 @@ internal class OperationsTypeRenderer( .forEach(::renderDslOp) private fun renderDslOp(op: Operation) { - val builderType = BuilderRenderer.builderType(op.request.type) + val builderType = BuilderRenderer.builderType(op.request) val generics = op.request.genericVars().asParamsList(" ") if (op.paginationInfo != null) renderManualPaginationAnnotation(op) else blankLine() diff --git a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/rendering/PaginatorRenderer.kt b/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/rendering/PaginatorRenderer.kt index e4fc8f6097a..74ea929b053 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/rendering/PaginatorRenderer.kt +++ b/hll/dynamodb-mapper/dynamodb-mapper-ops-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/operations/rendering/PaginatorRenderer.kt @@ -89,12 +89,9 @@ internal class PaginatorRenderer( private val paginationInfo = requireNotNull(op.paginationInfo) { "Operation ${op.name} is not paginatable" } private val name = paginatorName(op) - private val requestType = op.request.type - private val requestBuilderType = BuilderRenderer.builderType(requestType) - private val responseType = op.response.type - + private val requestBuilderType = BuilderRenderer.builderType(op.request) private val itemFlowType = Types.Kotlinx.Coroutines.Flow.flow(TypeVar("T")) - private val pageFlowType = Types.Kotlinx.Coroutines.Flow.flow(responseType) + private val pageFlowType = Types.Kotlinx.Coroutines.Flow.flow(op.response.type) fun render() { if (forResponses) { @@ -147,7 +144,7 @@ internal class PaginatorRenderer( "#L(initialRequest: #T): #T = #T {", "}", name, - requestType, + op.request.type, pageFlowType, Types.Kotlinx.Coroutines.Flow.flow, ) { diff --git a/hll/dynamodb-mapper/dynamodb-mapper-schema-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/annotations/rendering/SchemaRenderer.kt b/hll/dynamodb-mapper/dynamodb-mapper-schema-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/annotations/rendering/SchemaRenderer.kt index 950efe6c1bf..dd0df829a13 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-schema-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/annotations/rendering/SchemaRenderer.kt +++ b/hll/dynamodb-mapper/dynamodb-mapper-schema-codegen/src/main/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/codegen/annotations/rendering/SchemaRenderer.kt @@ -9,6 +9,8 @@ import aws.sdk.kotlin.hll.codegen.model.* import aws.sdk.kotlin.hll.codegen.rendering.BuilderRenderer import aws.sdk.kotlin.hll.codegen.rendering.RenderContext import aws.sdk.kotlin.hll.codegen.rendering.RendererBase +import aws.sdk.kotlin.hll.codegen.util.generatedAnnotation +import aws.sdk.kotlin.hll.codegen.util.plus import aws.sdk.kotlin.hll.codegen.util.visibility import aws.sdk.kotlin.hll.dynamodbmapper.* import aws.sdk.kotlin.hll.dynamodbmapper.codegen.annotations.AnnotationsProcessorOptions @@ -32,6 +34,7 @@ internal class SchemaRenderer( private val ctx: RenderContext, ) : RendererBase(ctx, "${classDeclaration.qualifiedName!!.getShortName()}Schema") { private val className = classDeclaration.qualifiedName!!.getShortName() + private val classStructure = Structure.from(classDeclaration) private val classType = Type.from(classDeclaration) private val builderName = "${className}Builder" @@ -104,12 +107,23 @@ internal class SchemaRenderer( } private fun renderBuilder() { - val members = properties.map(Member.Companion::from).toSet() - BuilderRenderer(this, classType, classType, members, ctx).render() + val builderCtx = ctx.copy( + attributes = ctx.attributes + (ModelAttributes.GeneratedApi to true), + ) + val members = properties.map(Member::from).toSet() + BuilderRenderer(this, classStructure, classType, members, builderCtx).render() } private fun renderItemConverter() { - withBlock("#Lobject #L : #T by #T(", ")", ctx.attributes.visibility, converterName, MapperTypes.Items.itemConverter(classType), MapperTypes.Items.SimpleItemConverter) { + generatedAnnotation() + withBlock( + "#Lobject #L : #T by #T(", + ")", + ctx.attributes.visibility, + converterName, + MapperTypes.Items.itemConverter(classType), + MapperTypes.Items.SimpleItemConverter, + ) { if (shouldRenderBuilder) { write("builderFactory = ::#L,", builderName) write("build = #L::build,", builderName) @@ -133,6 +147,7 @@ internal class SchemaRenderer( */ private fun renderValueConverter() { // TODO Offer alternate serialization options besides AttributeValue.M? + generatedAnnotation() write( "#Lval #L : #T = #T.#T(#T)", ctx.attributes.visibility, @@ -304,17 +319,18 @@ internal class SchemaRenderer( MapperTypes.Items.itemSchemaCompositeKey(classType, partitionKeyTypeRefs, sortKeyTypeRefs) } + generatedAnnotation() withBlock("#Lobject #L : #T {", "}", ctx.attributes.visibility, schemaName, schemaType) { write("override val converter: #1T = #1T", itemConverter) writeInline("override val partitionKey: #T = ", MapperTypes.Items.keySpec(partitionKeyTypeRefs)) keySpecInstantiation(partitionKeyProps) - write() + newline() if (sortKeyProps.isNotEmpty()) { writeInline("override val sortKey: #T = ", MapperTypes.Items.keySpec(sortKeyTypeRefs)) keySpecInstantiation(sortKeyProps) - write() + newline() } } @@ -369,6 +385,7 @@ internal class SchemaRenderer( MapperTypes.Model.tableCompositeKey(classType, partitionKeyTypeRefs, sortKeyTypeRefs) } + generatedAnnotation() val fnName = "get${className}Table" write( "#Lfun #T.#L(name: String): #T = #L(name, #L)", diff --git a/hll/dynamodb-mapper/dynamodb-mapper-schema-generator-plugin/src/test/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/plugins/SchemaGeneratorPluginTest.kt b/hll/dynamodb-mapper/dynamodb-mapper-schema-generator-plugin/src/test/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/plugins/SchemaGeneratorPluginTest.kt index bf2234b0089..f4182593c2b 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper-schema-generator-plugin/src/test/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/plugins/SchemaGeneratorPluginTest.kt +++ b/hll/dynamodb-mapper/dynamodb-mapper-schema-generator-plugin/src/test/kotlin/aws/sdk/kotlin/hll/dynamodbmapper/plugins/SchemaGeneratorPluginTest.kt @@ -91,17 +91,43 @@ class SchemaGeneratorPluginTest { val schemaContents = schemaFile.readText() // Builder - assertContains(schemaContents, "public class UserBuilder") - assertContains(schemaContents, "public var id: Int? = null") - assertContains(schemaContents, "public var givenName: String? = null") - assertContains(schemaContents, "public var surname: String? = null") - assertContains(schemaContents, "public var age: Int? = null") - assertContains(schemaContents, "public fun build(): User") + assertContains( + schemaContents, + """ + @GeneratedApi + public class UserBuilder { + @GeneratedApi + public var id: Int? = null + @GeneratedApi + public var givenName: String? = null + @GeneratedApi + public var surname: String? = null + @GeneratedApi + public var age: Int? = null + + @GeneratedApi + public fun build(): User { + val id = requireNotNull(id) { "Missing value for id" } + val givenName = requireNotNull(givenName) { "Missing value for givenName" } + val surname = requireNotNull(surname) { "Missing value for surname" } + val age = requireNotNull(age) { "Missing value for age" } + + return User( + id, + givenName, + surname, + age, + ) + } + } + """.trimIndent(), + ) // Converter assertContains( schemaContents, """ + @GeneratedApi public object UserConverter : ItemConverter by SimpleItemConverter( builderFactory = ::UserBuilder, build = UserBuilder::build, @@ -139,6 +165,7 @@ class SchemaGeneratorPluginTest { assertContains( schemaContents, """ + @GeneratedApi public object UserSchema : ItemSchema.PartitionKey> { override val converter: UserConverter = UserConverter override val partitionKey: KeySpec.Key1 = KeySpec.number("id") @@ -149,7 +176,10 @@ class SchemaGeneratorPluginTest { // GetTable assertContains( schemaContents, - "public fun DynamoDbMapper.getUserTable(name: String): Table.PartitionKey> = getTable(name, UserSchema)", + """ + @GeneratedApi + public fun DynamoDbMapper.getUserTable(name: String): Table.PartitionKey> = getTable(name, UserSchema) + """.trimIndent(), ) } @@ -172,6 +202,7 @@ class SchemaGeneratorPluginTest { assertContains( schemaContents, """ + @GeneratedApi public object BuilderNotRequiredConverter : ItemConverter by SimpleItemConverter( builderFactory = { BuilderNotRequired() }, build = { this }, @@ -229,12 +260,37 @@ class SchemaGeneratorPluginTest { val schemaContents = schemaFile.readText() // Assert a builder is still generated, because we configured GenerateBuilderClasses.ALWAYS - assertContains(schemaContents, "public class BuilderNotRequiredBuilder") - assertContains(schemaContents, "public var id: Int? = null") - assertContains(schemaContents, "public var givenName: String? = null") - assertContains(schemaContents, "public var surname: String? = null") - assertContains(schemaContents, "public var age: Int? = null") - assertContains(schemaContents, "public fun build(): BuilderNotRequired") + assertContains( + schemaContents, + """ + @GeneratedApi + public class BuilderNotRequiredBuilder { + @GeneratedApi + public var id: Int? = null + @GeneratedApi + public var givenName: String? = null + @GeneratedApi + public var surname: String? = null + @GeneratedApi + public var age: Int? = null + + @GeneratedApi + public fun build(): BuilderNotRequired { + val id = requireNotNull(id) { "Missing value for id" } + val givenName = requireNotNull(givenName) { "Missing value for givenName" } + val surname = requireNotNull(surname) { "Missing value for surname" } + val age = requireNotNull(age) { "Missing value for age" } + + return BuilderNotRequired( + id, + givenName, + surname, + age, + ) + } + } + """.trimIndent(), + ) } @Test @@ -382,12 +438,37 @@ class SchemaGeneratorPluginTest { val schemaContents = schemaFile.readText() - assertContains(schemaContents, "public class IgnoredProperty") - assertContains(schemaContents, "public var id: Int? = null") - assertContains(schemaContents, "public var givenName: String? = null") - assertContains(schemaContents, "public var surname: String? = null") - assertContains(schemaContents, "public var age: Int? = null") - assertContains(schemaContents, "public fun build(): IgnoredProperty") + assertContains( + schemaContents, + """ + @GeneratedApi + public class IgnoredPropertyBuilder { + @GeneratedApi + public var id: Int? = null + @GeneratedApi + public var givenName: String? = null + @GeneratedApi + public var surname: String? = null + @GeneratedApi + public var age: Int? = null + + @GeneratedApi + public fun build(): IgnoredProperty { + val id = requireNotNull(id) { "Missing value for id" } + val givenName = requireNotNull(givenName) { "Missing value for givenName" } + val surname = requireNotNull(surname) { "Missing value for surname" } + val age = requireNotNull(age) { "Missing value for age" } + + return IgnoredProperty( + id, + givenName, + surname, + age, + ) + } + } + """.trimIndent() + ) // ssn is annotated with DynamoDbIgnore assertFalse(schemaContents.contains("public var ssn: String? = null")) @@ -409,6 +490,7 @@ class SchemaGeneratorPluginTest { assertContains( schemaContents, """ + @GeneratedApi public object CustomUserSchema : ItemSchema.PartitionKey> { override val converter: MyCustomUserConverter = MyCustomUserConverter override val partitionKey: KeySpec.Key1 = KeySpec.number("id") @@ -565,6 +647,7 @@ class SchemaGeneratorPluginTest { assertContains( schemaContents, """ + @GeneratedApi public object RenamedPartitionKeySchema : ItemSchema.PartitionKey> { override val converter: RenamedPartitionKeyConverter = RenamedPartitionKeyConverter override val partitionKey: KeySpec.Key1 = KeySpec.number("user_id") diff --git a/hll/dynamodb-mapper/dynamodb-mapper/api/dynamodb-mapper.api b/hll/dynamodb-mapper/dynamodb-mapper/api/dynamodb-mapper.api index 81221f6f0da..35d0becf65d 100644 --- a/hll/dynamodb-mapper/dynamodb-mapper/api/dynamodb-mapper.api +++ b/hll/dynamodb-mapper/dynamodb-mapper/api/dynamodb-mapper.api @@ -969,15 +969,7 @@ public final class aws/sdk/kotlin/hll/dynamodbmapper/operations/DeleteItemReques public fun ()V public final fun build ()Laws/sdk/kotlin/hll/dynamodbmapper/operations/DeleteItemRequest; public final fun getKey ()Ljava/lang/Object; - public final fun getReturnConsumedCapacity ()Laws/sdk/kotlin/services/dynamodb/model/ReturnConsumedCapacity; - public final fun getReturnItemCollectionMetrics ()Laws/sdk/kotlin/services/dynamodb/model/ReturnItemCollectionMetrics; - public final fun getReturnValues ()Laws/sdk/kotlin/services/dynamodb/model/ReturnValue; - public final fun getReturnValuesOnConditionCheckFailure ()Laws/sdk/kotlin/services/dynamodb/model/ReturnValuesOnConditionCheckFailure; public final fun setKey (Ljava/lang/Object;)V - public final fun setReturnConsumedCapacity (Laws/sdk/kotlin/services/dynamodb/model/ReturnConsumedCapacity;)V - public final fun setReturnItemCollectionMetrics (Laws/sdk/kotlin/services/dynamodb/model/ReturnItemCollectionMetrics;)V - public final fun setReturnValues (Laws/sdk/kotlin/services/dynamodb/model/ReturnValue;)V - public final fun setReturnValuesOnConditionCheckFailure (Laws/sdk/kotlin/services/dynamodb/model/ReturnValuesOnConditionCheckFailure;)V } public abstract interface class aws/sdk/kotlin/hll/dynamodbmapper/operations/DeleteItemResponse { @@ -994,11 +986,7 @@ public final class aws/sdk/kotlin/hll/dynamodbmapper/operations/DeleteItemRespon public fun ()V public final fun build ()Laws/sdk/kotlin/hll/dynamodbmapper/operations/DeleteItemResponse; public final fun getAttributes ()Ljava/lang/Object; - public final fun getConsumedCapacity ()Laws/sdk/kotlin/services/dynamodb/model/ConsumedCapacity; - public final fun getItemCollectionMetrics ()Laws/sdk/kotlin/services/dynamodb/model/ItemCollectionMetrics; public final fun setAttributes (Ljava/lang/Object;)V - public final fun setConsumedCapacity (Laws/sdk/kotlin/services/dynamodb/model/ConsumedCapacity;)V - public final fun setItemCollectionMetrics (Laws/sdk/kotlin/services/dynamodb/model/ItemCollectionMetrics;)V } public final class aws/sdk/kotlin/hll/dynamodbmapper/operations/GetItemKt { @@ -1023,12 +1011,8 @@ public final class aws/sdk/kotlin/hll/dynamodbmapper/operations/GetItemRequest$C public final class aws/sdk/kotlin/hll/dynamodbmapper/operations/GetItemRequestBuilder { public fun ()V public final fun build ()Laws/sdk/kotlin/hll/dynamodbmapper/operations/GetItemRequest; - public final fun getConsistentRead ()Ljava/lang/Boolean; public final fun getKey ()Ljava/lang/Object; - public final fun getReturnConsumedCapacity ()Laws/sdk/kotlin/services/dynamodb/model/ReturnConsumedCapacity; - public final fun setConsistentRead (Ljava/lang/Boolean;)V public final fun setKey (Ljava/lang/Object;)V - public final fun setReturnConsumedCapacity (Laws/sdk/kotlin/services/dynamodb/model/ReturnConsumedCapacity;)V } public abstract interface class aws/sdk/kotlin/hll/dynamodbmapper/operations/GetItemResponse { @@ -1043,9 +1027,7 @@ public final class aws/sdk/kotlin/hll/dynamodbmapper/operations/GetItemResponse$ public final class aws/sdk/kotlin/hll/dynamodbmapper/operations/GetItemResponseBuilder { public fun ()V public final fun build ()Laws/sdk/kotlin/hll/dynamodbmapper/operations/GetItemResponse; - public final fun getConsumedCapacity ()Laws/sdk/kotlin/services/dynamodb/model/ConsumedCapacity; public final fun getItem ()Ljava/lang/Object; - public final fun setConsumedCapacity (Laws/sdk/kotlin/services/dynamodb/model/ConsumedCapacity;)V public final fun setItem (Ljava/lang/Object;)V } @@ -1102,15 +1084,7 @@ public final class aws/sdk/kotlin/hll/dynamodbmapper/operations/PutItemRequestBu public fun ()V public final fun build ()Laws/sdk/kotlin/hll/dynamodbmapper/operations/PutItemRequest; public final fun getItem ()Ljava/lang/Object; - public final fun getReturnConsumedCapacity ()Laws/sdk/kotlin/services/dynamodb/model/ReturnConsumedCapacity; - public final fun getReturnItemCollectionMetrics ()Laws/sdk/kotlin/services/dynamodb/model/ReturnItemCollectionMetrics; - public final fun getReturnValues ()Laws/sdk/kotlin/services/dynamodb/model/ReturnValue; - public final fun getReturnValuesOnConditionCheckFailure ()Laws/sdk/kotlin/services/dynamodb/model/ReturnValuesOnConditionCheckFailure; public final fun setItem (Ljava/lang/Object;)V - public final fun setReturnConsumedCapacity (Laws/sdk/kotlin/services/dynamodb/model/ReturnConsumedCapacity;)V - public final fun setReturnItemCollectionMetrics (Laws/sdk/kotlin/services/dynamodb/model/ReturnItemCollectionMetrics;)V - public final fun setReturnValues (Laws/sdk/kotlin/services/dynamodb/model/ReturnValue;)V - public final fun setReturnValuesOnConditionCheckFailure (Laws/sdk/kotlin/services/dynamodb/model/ReturnValuesOnConditionCheckFailure;)V } public abstract interface class aws/sdk/kotlin/hll/dynamodbmapper/operations/PutItemResponse { @@ -1127,11 +1101,7 @@ public final class aws/sdk/kotlin/hll/dynamodbmapper/operations/PutItemResponseB public fun ()V public final fun build ()Laws/sdk/kotlin/hll/dynamodbmapper/operations/PutItemResponse; public final fun getAttributes ()Ljava/lang/Object; - public final fun getConsumedCapacity ()Laws/sdk/kotlin/services/dynamodb/model/ConsumedCapacity; - public final fun getItemCollectionMetrics ()Laws/sdk/kotlin/services/dynamodb/model/ItemCollectionMetrics; public final fun setAttributes (Ljava/lang/Object;)V - public final fun setConsumedCapacity (Laws/sdk/kotlin/services/dynamodb/model/ConsumedCapacity;)V - public final fun setItemCollectionMetrics (Laws/sdk/kotlin/services/dynamodb/model/ItemCollectionMetrics;)V } public final class aws/sdk/kotlin/hll/dynamodbmapper/operations/QueryKt { @@ -1162,22 +1132,12 @@ public final class aws/sdk/kotlin/hll/dynamodbmapper/operations/QueryRequestBuil public fun ()V public final fun build ()Laws/sdk/kotlin/hll/dynamodbmapper/operations/QueryRequest; public final fun filter (Lkotlin/jvm/functions/Function1;)V - public final fun getConsistentRead ()Ljava/lang/Boolean; public final fun getExclusiveStartKey ()Ljava/lang/Object; public final fun getFilter ()Laws/sdk/kotlin/hll/dynamodbmapper/expressions/BooleanExpr; public final fun getKeyCondition ()Laws/sdk/kotlin/hll/dynamodbmapper/expressions/KeyFilter; - public final fun getLimit ()Ljava/lang/Integer; - public final fun getReturnConsumedCapacity ()Laws/sdk/kotlin/services/dynamodb/model/ReturnConsumedCapacity; - public final fun getScanIndexForward ()Ljava/lang/Boolean; - public final fun getSelect ()Laws/sdk/kotlin/services/dynamodb/model/Select; - public final fun setConsistentRead (Ljava/lang/Boolean;)V public final fun setExclusiveStartKey (Ljava/lang/Object;)V public final fun setFilter (Laws/sdk/kotlin/hll/dynamodbmapper/expressions/BooleanExpr;)V public final fun setKeyCondition (Laws/sdk/kotlin/hll/dynamodbmapper/expressions/KeyFilter;)V - public final fun setLimit (Ljava/lang/Integer;)V - public final fun setReturnConsumedCapacity (Laws/sdk/kotlin/services/dynamodb/model/ReturnConsumedCapacity;)V - public final fun setScanIndexForward (Ljava/lang/Boolean;)V - public final fun setSelect (Laws/sdk/kotlin/services/dynamodb/model/Select;)V } public abstract interface class aws/sdk/kotlin/hll/dynamodbmapper/operations/QueryResponse { @@ -1195,16 +1155,10 @@ public final class aws/sdk/kotlin/hll/dynamodbmapper/operations/QueryResponse$Co public final class aws/sdk/kotlin/hll/dynamodbmapper/operations/QueryResponseBuilder { public fun ()V public final fun build ()Laws/sdk/kotlin/hll/dynamodbmapper/operations/QueryResponse; - public final fun getConsumedCapacity ()Laws/sdk/kotlin/services/dynamodb/model/ConsumedCapacity; - public final fun getCount ()Ljava/lang/Integer; public final fun getItems ()Ljava/util/List; public final fun getLastEvaluatedKey ()Ljava/lang/Object; - public final fun getScannedCount ()Ljava/lang/Integer; - public final fun setConsumedCapacity (Laws/sdk/kotlin/services/dynamodb/model/ConsumedCapacity;)V - public final fun setCount (Ljava/lang/Integer;)V public final fun setItems (Ljava/util/List;)V public final fun setLastEvaluatedKey (Ljava/lang/Object;)V - public final fun setScannedCount (Ljava/lang/Integer;)V } public final class aws/sdk/kotlin/hll/dynamodbmapper/operations/ScanKt { @@ -1235,22 +1189,10 @@ public final class aws/sdk/kotlin/hll/dynamodbmapper/operations/ScanRequestBuild public fun ()V public final fun build ()Laws/sdk/kotlin/hll/dynamodbmapper/operations/ScanRequest; public final fun filter (Lkotlin/jvm/functions/Function1;)V - public final fun getConsistentRead ()Ljava/lang/Boolean; public final fun getExclusiveStartKey ()Ljava/lang/Object; public final fun getFilter ()Laws/sdk/kotlin/hll/dynamodbmapper/expressions/BooleanExpr; - public final fun getLimit ()Ljava/lang/Integer; - public final fun getReturnConsumedCapacity ()Laws/sdk/kotlin/services/dynamodb/model/ReturnConsumedCapacity; - public final fun getSegment ()Ljava/lang/Integer; - public final fun getSelect ()Laws/sdk/kotlin/services/dynamodb/model/Select; - public final fun getTotalSegments ()Ljava/lang/Integer; - public final fun setConsistentRead (Ljava/lang/Boolean;)V public final fun setExclusiveStartKey (Ljava/lang/Object;)V public final fun setFilter (Laws/sdk/kotlin/hll/dynamodbmapper/expressions/BooleanExpr;)V - public final fun setLimit (Ljava/lang/Integer;)V - public final fun setReturnConsumedCapacity (Laws/sdk/kotlin/services/dynamodb/model/ReturnConsumedCapacity;)V - public final fun setSegment (Ljava/lang/Integer;)V - public final fun setSelect (Laws/sdk/kotlin/services/dynamodb/model/Select;)V - public final fun setTotalSegments (Ljava/lang/Integer;)V } public abstract interface class aws/sdk/kotlin/hll/dynamodbmapper/operations/ScanResponse { @@ -1268,16 +1210,10 @@ public final class aws/sdk/kotlin/hll/dynamodbmapper/operations/ScanResponse$Com public final class aws/sdk/kotlin/hll/dynamodbmapper/operations/ScanResponseBuilder { public fun ()V public final fun build ()Laws/sdk/kotlin/hll/dynamodbmapper/operations/ScanResponse; - public final fun getConsumedCapacity ()Laws/sdk/kotlin/services/dynamodb/model/ConsumedCapacity; - public final fun getCount ()Ljava/lang/Integer; public final fun getItems ()Ljava/util/List; public final fun getLastEvaluatedKey ()Ljava/lang/Object; - public final fun getScannedCount ()Ljava/lang/Integer; - public final fun setConsumedCapacity (Laws/sdk/kotlin/services/dynamodb/model/ConsumedCapacity;)V - public final fun setCount (Ljava/lang/Integer;)V public final fun setItems (Ljava/util/List;)V public final fun setLastEvaluatedKey (Ljava/lang/Object;)V - public final fun setScannedCount (Ljava/lang/Integer;)V } public abstract interface class aws/sdk/kotlin/hll/dynamodbmapper/operations/TableOperations : aws/sdk/kotlin/hll/dynamodbmapper/operations/ItemSourceOperations { diff --git a/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/core/CodeGenerator.kt b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/core/CodeGenerator.kt index d1819e590c2..adb4d15f83e 100644 --- a/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/core/CodeGenerator.kt +++ b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/core/CodeGenerator.kt @@ -118,7 +118,7 @@ public interface CodeGenerator { /** * Writes a newline */ - public fun write() { + public fun newline() { write("") } diff --git a/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/HasAttributes.kt b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/HasAttributes.kt new file mode 100644 index 00000000000..ab50a510903 --- /dev/null +++ b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/HasAttributes.kt @@ -0,0 +1,13 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +package aws.sdk.kotlin.hll.codegen.model + +import aws.sdk.kotlin.runtime.InternalSdkApi +import aws.smithy.kotlin.runtime.collections.Attributes + +@InternalSdkApi +public interface HasAttributes { + public val attributes: Attributes +} diff --git a/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/HllTypes.kt b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/HllTypes.kt new file mode 100644 index 00000000000..4856b824e17 --- /dev/null +++ b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/HllTypes.kt @@ -0,0 +1,18 @@ +package aws.sdk.kotlin.hll.codegen.model + +import aws.sdk.kotlin.runtime.InternalSdkApi + +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +@InternalSdkApi +public object HllTypes { + @InternalSdkApi + public object SmithyKotlin { + @InternalSdkApi + public object RuntimeCore { + public val GeneratedApi: TypeRef = TypeRef("aws.smithy.kotlin.runtime", "GeneratedApi") + } + } +} diff --git a/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/Member.kt b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/Member.kt index 54d62727b03..5faefe930d6 100644 --- a/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/Member.kt +++ b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/Member.kt @@ -5,9 +5,7 @@ package aws.sdk.kotlin.hll.codegen.model import aws.sdk.kotlin.runtime.InternalSdkApi -import aws.smithy.kotlin.runtime.collections.Attributes -import aws.smithy.kotlin.runtime.collections.emptyAttributes -import aws.smithy.kotlin.runtime.collections.get +import aws.smithy.kotlin.runtime.collections.* import com.google.devtools.ksp.symbol.KSPropertyDeclaration /** @@ -22,18 +20,22 @@ public data class Member( val name: String, val type: Type, val mutable: Boolean = false, - val attributes: Attributes = emptyAttributes(), -) { + override val attributes: Attributes = emptyAttributes(), +) : HasAttributes { @InternalSdkApi public companion object { /** * Derive a [Member] from a [KSPropertyDeclaration] */ - public fun from(prop: KSPropertyDeclaration): Member { + public fun from( + prop: KSPropertyDeclaration, + additionalAttributes: AttributesBuilder.() -> Unit = { }, + ): Member { val member = Member( name = prop.simpleName.getShortName(), type = Type.from(prop.type), mutable = prop.isMutable, + attributes = attributesOf { additionalAttributes() }, ) return ModelParsingPlugin.transform(member, ModelParsingPlugin::postProcessMember) diff --git a/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/ModelAttributes.kt b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/ModelAttributes.kt index c99236819a7..355305657be 100644 --- a/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/ModelAttributes.kt +++ b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/ModelAttributes.kt @@ -6,6 +6,8 @@ package aws.sdk.kotlin.hll.codegen.model import aws.sdk.kotlin.runtime.InternalSdkApi import aws.smithy.kotlin.runtime.collections.AttributeKey +import aws.smithy.kotlin.runtime.collections.Attributes +import aws.smithy.kotlin.runtime.collections.MutableAttributes /** * Defines [AttributeKey] instances that relate to the data model of low-level to high-level codegen @@ -17,6 +19,11 @@ public object ModelAttributes { */ public val DslInfo: AttributeKey = AttributeKey("aws.sdk.kotlin.hll#DslInfo") + /** + * Specifies whether the given API declaration (e.g., method, field, parameter, etc.) is generated. + */ + public val GeneratedApi: AttributeKey = AttributeKey("aws.sdk.kotlin.hll.codegen#Generated") + /** * For a given high-level [Member], this attribute key identifies the associated low-level [Member] */ @@ -32,3 +39,12 @@ public object ModelAttributes { */ public val LowLevelStructure: AttributeKey = AttributeKey("aws.sdk.kotlin.hll#LowLevelStructure") } + +public val Attributes.generatedApi: Boolean + get() = this.getOrNull(ModelAttributes.GeneratedApi) ?: false + +public var MutableAttributes.generatedApi: Boolean + get() = this.getOrNull(ModelAttributes.GeneratedApi) ?: false + set(value) { + this.set(ModelAttributes.GeneratedApi, value) + } diff --git a/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/Operation.kt b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/Operation.kt index 95cb6ce1a73..55d0beafae4 100644 --- a/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/Operation.kt +++ b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/Operation.kt @@ -6,9 +6,7 @@ package aws.sdk.kotlin.hll.codegen.model import aws.sdk.kotlin.hll.codegen.util.capitalizeFirstChar import aws.sdk.kotlin.runtime.InternalSdkApi -import aws.smithy.kotlin.runtime.collections.Attributes -import aws.smithy.kotlin.runtime.collections.emptyAttributes -import aws.smithy.kotlin.runtime.collections.get +import aws.smithy.kotlin.runtime.collections.* import com.google.devtools.ksp.symbol.KSFunctionDeclaration /** @@ -24,8 +22,8 @@ public data class Operation( val methodName: String, val request: Structure, val response: Structure, - val attributes: Attributes = emptyAttributes(), -) { + override val attributes: Attributes = emptyAttributes(), +) : HasAttributes { /** * The capitalized name of this operation's [methodName]. For example, if [methodName] is `getItem` then [name] * would be `GetItem`. @@ -37,11 +35,15 @@ public data class Operation( /** * Derive an [Operation] from a [KSFunctionDeclaration] */ - public fun from(declaration: KSFunctionDeclaration): Operation { + public fun from( + declaration: KSFunctionDeclaration, + additionalAttributes: AttributesBuilder.() -> Unit = { }, + ): Operation { val op = Operation( methodName = declaration.simpleName.getShortName(), request = Structure.from(declaration.parameters.single().type), response = Structure.from(declaration.returnType!!), + attributes = attributesOf { additionalAttributes() }, ) return ModelParsingPlugin.transform(op, ModelParsingPlugin::postProcessOperation) diff --git a/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/Structure.kt b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/Structure.kt index a83f1308ebd..ea3c74840d4 100644 --- a/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/Structure.kt +++ b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/model/Structure.kt @@ -5,9 +5,7 @@ package aws.sdk.kotlin.hll.codegen.model import aws.sdk.kotlin.runtime.InternalSdkApi -import aws.smithy.kotlin.runtime.collections.Attributes -import aws.smithy.kotlin.runtime.collections.emptyAttributes -import aws.smithy.kotlin.runtime.collections.get +import aws.smithy.kotlin.runtime.collections.* import com.google.devtools.ksp.getDeclaredProperties import com.google.devtools.ksp.symbol.KSClassDeclaration import com.google.devtools.ksp.symbol.KSTypeReference @@ -22,24 +20,34 @@ import com.google.devtools.ksp.symbol.KSTypeReference public data class Structure( val type: TypeRef, val members: Set, - val attributes: Attributes = emptyAttributes(), -) { + override val attributes: Attributes = emptyAttributes(), +) : HasAttributes { @InternalSdkApi public companion object { /** - * Derives a [Structure] from the given [KSTypeReference] + * Derives a [Structure] from the given [KSClassDeclaration] */ - public fun from(ksTypeRef: KSTypeReference): Structure { + public fun from( + ksClassDeclaration: KSClassDeclaration, + additionalAttributes: AttributesBuilder.() -> Unit = { }, + ): Structure { val struct = Structure( - type = Type.from(ksTypeRef), - members = (ksTypeRef.resolve().declaration as KSClassDeclaration) + type = Type.from(ksClassDeclaration), + members = ksClassDeclaration .getDeclaredProperties() .map(Member.Companion::from) .toSet(), + attributes = attributesOf { additionalAttributes() }, ) return ModelParsingPlugin.transform(struct, ModelParsingPlugin::postProcessStructure) } + + /** + * Derives a [Structure] from the given [KSTypeReference] + */ + public fun from(ksTypeRef: KSTypeReference): Structure = + from(ksTypeRef.resolve().declaration as KSClassDeclaration) } } diff --git a/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/rendering/BuilderRenderer.kt b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/rendering/BuilderRenderer.kt index d904e042f75..b760d80b4fd 100644 --- a/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/rendering/BuilderRenderer.kt +++ b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/rendering/BuilderRenderer.kt @@ -7,14 +7,14 @@ package aws.sdk.kotlin.hll.codegen.rendering import aws.sdk.kotlin.hll.codegen.core.CodeGenerator import aws.sdk.kotlin.hll.codegen.model.* +import aws.sdk.kotlin.hll.codegen.util.generatedAnnotation import aws.sdk.kotlin.hll.codegen.util.visibility import aws.sdk.kotlin.runtime.InternalSdkApi /** * A DSL-style builder renderer. * @param generator The generator in which the builder will be written - * @param builtType The [TypeRef] representing the type for which a builder will be generated. This type can be a class - * or an interface. + * @param builtType The [Structure] for which a builder will be generated * @param implementationType The [TypeRef] representing the implementing type whose constructor will be called by the * generated `build` method. This type must expose a constructor which accepts each element of [members] as parameters. * Note that this type doesn't have to be public (merely accessible to the `build` method) and may be the same as @@ -25,28 +25,30 @@ import aws.sdk.kotlin.runtime.InternalSdkApi @InternalSdkApi public class BuilderRenderer( private val generator: CodeGenerator, - private val builtType: TypeRef, + private val builtStructure: Structure, private val implementationType: TypeRef, private val members: Set, private val ctx: RenderContext, ) : CodeGenerator by generator { @InternalSdkApi public companion object { - public fun builderName(builtType: TypeRef): String = "${builtType.shortName}Builder" - public fun builderType(builtType: TypeRef): TypeRef = builtType.copy(shortName = builderName(builtType)) + public fun builderName(builtType: Structure): String = "${builtType.type.shortName}Builder" + public fun builderType(builtType: Structure): TypeRef = builtType.type.copy(shortName = builderName(builtType)) } - private val builderName = builderName(builtType) + private val builtType = builtStructure.type + private val builderName = builderName(builtStructure) public fun render() { docs("A DSL-style builder for instances of [#T]", builtType) + generatedAnnotation(builtStructure, ctx) val genericParams = members.flatMap { it.type.genericVars() }.asParamsList() - withBlock("#Lclass #L#L {", "}", ctx.attributes.visibility, builderName, genericParams) { members.forEach(::renderProperty) blankLine() + generatedAnnotation(builtStructure, ctx) withBlock("#Lfun build(): #T {", "}", ctx.attributes.visibility, builtType, genericParams) { members.forEach { if (it.type.nullable) { @@ -73,10 +75,12 @@ public class BuilderRenderer( blankLine() } + generatedAnnotation(member, ctx) write("#Lvar #L: #T = null", ctx.attributes.visibility, member.name, member.type.nullable()) if (dslInfo != null) { blankLine() + generatedAnnotation(member, ctx) withBlock( "#Lfun #L(block: #T.() -> #T) {", "}", diff --git a/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/rendering/RenderContext.kt b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/rendering/RenderContext.kt index eaae066a5e1..da7c5bc2658 100644 --- a/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/rendering/RenderContext.kt +++ b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/rendering/RenderContext.kt @@ -5,6 +5,7 @@ package aws.sdk.kotlin.hll.codegen.rendering import aws.sdk.kotlin.hll.codegen.core.CodeGeneratorFactory +import aws.sdk.kotlin.hll.codegen.model.HasAttributes import aws.sdk.kotlin.runtime.InternalSdkApi import aws.smithy.kotlin.runtime.collections.Attributes import aws.smithy.kotlin.runtime.collections.emptyAttributes @@ -24,8 +25,8 @@ public data class RenderContext( val codegenFactory: CodeGeneratorFactory, val pkg: String, val rendererName: String = "aws-sdk-kotlin-hll-codegen", - val attributes: Attributes = emptyAttributes(), -) + override val attributes: Attributes = emptyAttributes(), +) : HasAttributes public fun RenderContext.logging(message: String, symbol: KSNode? = null): Unit = logger.logging(message, symbol) public fun RenderContext.info(message: String, symbol: KSNode? = null): Unit = logger.info(message, symbol) diff --git a/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/util/GeneratedApiUtils.kt b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/util/GeneratedApiUtils.kt new file mode 100644 index 00000000000..7541c0cea1f --- /dev/null +++ b/hll/hll-codegen/src/main/kotlin/aws/sdk/kotlin/hll/codegen/util/GeneratedApiUtils.kt @@ -0,0 +1,38 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ +package aws.sdk.kotlin.hll.codegen.util + +import aws.sdk.kotlin.hll.codegen.core.CodeGenerator +import aws.sdk.kotlin.hll.codegen.model.HasAttributes +import aws.sdk.kotlin.hll.codegen.model.HllTypes +import aws.sdk.kotlin.hll.codegen.model.generatedApi +import aws.sdk.kotlin.runtime.InternalSdkApi +import aws.smithy.kotlin.runtime.collections.Attributes + +/** + * Writes a `@GeneratedApi` annotation if the given [subject]'s attributes have [generatedApi] set + */ +@InternalSdkApi +public fun CodeGenerator.generatedAnnotation(vararg subjects: HasAttributes): Unit = + generatedAnnotation(*subjects.map { it.attributes }.toTypedArray()) + +/** + * Writes a `@GeneratedApi` annotation if the given [subjectAttributes] have [generatedApi] set + */ +@InternalSdkApi +public fun CodeGenerator.generatedAnnotation(vararg subjectAttributes: Attributes) { + if (subjectAttributes.any { it.generatedApi }) { + generatedAnnotation() + } +} + + +/** + * Writes a `@GeneratedApi` annotation + */ +@InternalSdkApi +public fun CodeGenerator.generatedAnnotation() { + write("@#T", HllTypes.SmithyKotlin.RuntimeCore.GeneratedApi) +}