diff --git a/CHANGELOG.next.toml b/CHANGELOG.next.toml index ddb541e1d5..c8446ae7de 100644 --- a/CHANGELOG.next.toml +++ b/CHANGELOG.next.toml @@ -73,7 +73,6 @@ references = ["smithy-rs#1603", "aws-sdk-rust#586"] meta = { "breaking" = true, "tada" = false, "bug" = false, "target" = "client" } author = "jdisanti" - [[aws-sdk-rust]] message = """ Implemented customizable operations per [RFC-0017](https://awslabs.github.io/smithy-rs/design/rfcs/rfc0017_customizable_client_operations.html). @@ -169,3 +168,9 @@ let response = client.some_operation() references = ["smithy-rs#1647", "smithy-rs#1112"] meta = { "breaking" = false, "tada" = true, "bug" = false, "target" = "client"} author = "Velfi" + +[[smithy-rs]] +message = "Smithy IDL v2 mixins are now supported" +references = ["smithy-rs#1680"] +meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "all"} +author = "ogudavid" diff --git a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt index c07e952373..1b28ee8599 100644 --- a/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt +++ b/codegen-server/src/main/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitor.kt @@ -103,6 +103,8 @@ open class ServerCodegenVisitor( */ protected fun baselineTransform(model: Model) = model + // Flattens mixins out of the model and removes them from the model + .let { ModelTransformer.create().flattenAndRemoveMixins(it) } // Add errors attached at the service level to the models .let { ModelTransformer.create().copyServiceErrorsToOperations(it, settings.getService(it)) } // Add `Box` to recursive shapes as necessary @@ -114,6 +116,12 @@ open class ServerCodegenVisitor( // Normalize event stream operations .let(EventStreamNormalizer::transform) + /** + * Exposure purely for unit test purposes. + */ + internal fun baselineTransformInternalTest(model: Model) = + baselineTransform(model) + /** * Execute code generation * diff --git a/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitorTest.kt b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitorTest.kt new file mode 100644 index 0000000000..ccfc11ab38 --- /dev/null +++ b/codegen-server/src/test/kotlin/software/amazon/smithy/rust/codegen/server/smithy/ServerCodegenVisitorTest.kt @@ -0,0 +1,57 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.rust.codegen.server.smithy + +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.Test +import software.amazon.smithy.model.shapes.ShapeId +import software.amazon.smithy.rust.codegen.server.smithy.customizations.ServerRequiredCustomizations +import software.amazon.smithy.rust.codegen.smithy.ServerCodegenContext +import software.amazon.smithy.rust.codegen.smithy.customize.CombinedCodegenDecorator +import software.amazon.smithy.rust.codegen.testutil.asSmithyModel +import software.amazon.smithy.rust.codegen.testutil.generatePluginContext +import kotlin.io.path.createDirectory +import kotlin.io.path.writeText + +class ServerCodegenVisitorTest { + @Test + fun `baseline transform verify mixins removed`() { + val model = """ + namespace com.example + + use aws.protocols#awsJson1_0 + + @awsJson1_0 + @aws.api#service(sdkId: "Test", endpointPrefix: "differentPrefix") + service Example { + operations: [ BasicOperation ] + } + + operation BasicOperation { + input: Shape + } + + @mixin + structure SimpleMixin { + name: String + } + + structure Shape with [ + SimpleMixin + ] { + greeting: String + } + """.asSmithyModel(smithyVersion = "2.0") + val (ctx, testDir) = generatePluginContext(model) + testDir.resolve("src").createDirectory() + testDir.resolve("src/main.rs").writeText("fn main() {}") + val codegenDecorator: CombinedCodegenDecorator = + CombinedCodegenDecorator.fromClasspath(ctx, ServerRequiredCustomizations()) + val visitor = ServerCodegenVisitor(ctx, codegenDecorator) + val baselineModel = visitor.baselineTransformInternalTest(model) + baselineModel.getShapesWithTrait(ShapeId.from("smithy.api#mixin")).isEmpty() shouldBe true + } +} diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/CodegenVisitor.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/CodegenVisitor.kt index e5c133f32c..184b94581c 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/CodegenVisitor.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/smithy/CodegenVisitor.kt @@ -86,8 +86,10 @@ class CodegenVisitor(context: PluginContext, private val codegenDecorator: RustC * Base model transformation applied to all services * See below for details. */ - private fun baselineTransform(model: Model) = + internal fun baselineTransform(model: Model) = model + // Flattens mixins out of the model and removes them from the model + .let { ModelTransformer.create().flattenAndRemoveMixins(it) } // Add errors attached at the service level to the models .let { ModelTransformer.create().copyServiceErrorsToOperations(it, settings.getService(it)) } // Add `Box` to recursive shapes as necessary diff --git a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/testutil/TestHelpers.kt b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/testutil/TestHelpers.kt index 7883f79b67..55cc877c22 100644 --- a/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/testutil/TestHelpers.kt +++ b/codegen/src/main/kotlin/software/amazon/smithy/rust/codegen/testutil/TestHelpers.kt @@ -88,8 +88,8 @@ fun testCodegenContext( ) private const val SmithyVersion = "1.0" -fun String.asSmithyModel(sourceLocation: String? = null): Model { - val processed = letIf(!this.startsWith("\$version")) { "\$version: ${SmithyVersion.dq()}\n$it" } +fun String.asSmithyModel(sourceLocation: String? = null, smithyVersion: String = SmithyVersion): Model { + val processed = letIf(!this.startsWith("\$version")) { "\$version: ${smithyVersion.dq()}\n$it" } return Model.assembler().discoverModels().addUnparsedModel(sourceLocation ?: "test.smithy", processed).assemble() .unwrap() } diff --git a/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/CodegenVisitorTest.kt b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/CodegenVisitorTest.kt new file mode 100644 index 0000000000..85cf6ee8a0 --- /dev/null +++ b/codegen/src/test/kotlin/software/amazon/smithy/rust/codegen/smithy/CodegenVisitorTest.kt @@ -0,0 +1,65 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.rust.codegen.smithy + +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.Test +import software.amazon.smithy.model.shapes.ShapeId +import software.amazon.smithy.rust.codegen.smithy.customizations.ClientCustomizations +import software.amazon.smithy.rust.codegen.smithy.customize.CombinedCodegenDecorator +import software.amazon.smithy.rust.codegen.smithy.customize.NoOpEventStreamSigningDecorator +import software.amazon.smithy.rust.codegen.smithy.customize.RequiredCustomizations +import software.amazon.smithy.rust.codegen.smithy.generators.client.FluentClientDecorator +import software.amazon.smithy.rust.codegen.testutil.asSmithyModel +import software.amazon.smithy.rust.codegen.testutil.generatePluginContext +import kotlin.io.path.createDirectory +import kotlin.io.path.writeText + +class CodegenVisitorTest { + @Test + fun `baseline transform verify mixins removed`() { + val model = """ + namespace com.example + + use aws.protocols#awsJson1_0 + + @awsJson1_0 + @aws.api#service(sdkId: "Test", endpointPrefix: "differentPrefix") + service Example { + operations: [ BasicOperation ] + } + + operation BasicOperation { + input: Shape + } + + @mixin + structure SimpleMixin { + name: String + } + + structure Shape with [ + SimpleMixin + ] { + greeting: String + } + """.asSmithyModel(smithyVersion = "2.0") + val (ctx, testDir) = generatePluginContext(model) + testDir.resolve("src").createDirectory() + testDir.resolve("src/main.rs").writeText("fn main() {}") + val codegenDecorator = + CombinedCodegenDecorator.fromClasspath( + ctx, + ClientCustomizations(), + RequiredCustomizations(), + FluentClientDecorator(), + NoOpEventStreamSigningDecorator(), + ) + val visitor = CodegenVisitor(ctx, codegenDecorator) + val baselineModel = visitor.baselineTransform(model) + baselineModel.getShapesWithTrait(ShapeId.from("smithy.api#mixin")).isEmpty() shouldBe true + } +}