From d0e98d65cb1cd57deb984a2cc5ae796448cad302 Mon Sep 17 00:00:00 2001
From: Josh Elkins <jbelkins@amazon.com>
Date: Tue, 17 Jun 2025 11:07:07 -0500
Subject: [PATCH 1/3] chore: Update Smithy to 1.59.0

---
 gradle.properties                                         | 2 +-
 .../amazon/smithy/swift/codegen/ShapeValueGenerator.kt    | 8 ++++++++
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/gradle.properties b/gradle.properties
index 563075c1d..ae8af99c5 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -3,7 +3,7 @@ kotlin.code.style=official
 # config
 
 # codegen
-smithyVersion=1.54.0
+smithyVersion=1.59.0
 smithyGradleVersion=0.6.0
 
 # kotlin
diff --git a/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/ShapeValueGenerator.kt b/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/ShapeValueGenerator.kt
index 61d276df8..ede388fa7 100644
--- a/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/ShapeValueGenerator.kt
+++ b/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/ShapeValueGenerator.kt
@@ -10,6 +10,7 @@ import software.amazon.smithy.model.Model
 import software.amazon.smithy.model.node.ArrayNode
 import software.amazon.smithy.model.node.BooleanNode
 import software.amazon.smithy.model.node.Node
+import software.amazon.smithy.model.node.NodeType
 import software.amazon.smithy.model.node.NodeVisitor
 import software.amazon.smithy.model.node.NullNode
 import software.amazon.smithy.model.node.NumberNode
@@ -54,6 +55,13 @@ class ShapeValueGenerator(
         shape: Shape,
         params: Node,
     ) {
+        // If the node for the value to be written is NULL, then the value for this shape is not present.
+        // Just write a Swift `nil` and stop rendering.
+        if (params.type == NodeType.NULL) {
+            writer.writeInline("nil")
+            return
+        }
+
         val nodeVisitor = ShapeValueNodeVisitor(writer, this, shape)
 
         when (shape.type) {

From 8c9f0fc3bb61c058c772dd3763fe1bfe0bbf51c3 Mon Sep 17 00:00:00 2001
From: Josh Elkins <jbelkins@amazon.com>
Date: Tue, 17 Jun 2025 15:03:37 -0500
Subject: [PATCH 2/3] Fix protocol tests, warnings; refactor Header

---
 Sources/SmithyHTTPAPI/Headers.swift                   |  8 +++-----
 .../OperationEndpointResolverMiddleware.kt            | 11 ++++++++++-
 .../middlewares/providers/HttpHeaderProvider.kt       |  4 ++++
 3 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/Sources/SmithyHTTPAPI/Headers.swift b/Sources/SmithyHTTPAPI/Headers.swift
index bf9100359..40b52cdae 100644
--- a/Sources/SmithyHTTPAPI/Headers.swift
+++ b/Sources/SmithyHTTPAPI/Headers.swift
@@ -191,11 +191,9 @@ extension Headers: Equatable {
     ///   - rhs: The second `Headers` to compare.
     /// - Returns: `true` if the two values are equal irrespective of order, otherwise `false`.
     public static func == (lhs: Headers, rhs: Headers) -> Bool {
-        lhs.access { lhsHeaders in
-            rhs.access { rhsHeaders in
-                lhsHeaders.sorted() == rhsHeaders.sorted()
-            }
-        }
+        let lhsHeaders = lhs.access { $0 }.sorted()
+        let rhsHeaders = rhs.access { $0 }.sorted()
+        return lhsHeaders == rhsHeaders
     }
 }
 
diff --git a/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/middlewares/OperationEndpointResolverMiddleware.kt b/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/middlewares/OperationEndpointResolverMiddleware.kt
index 294094ae6..aaeff3714 100644
--- a/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/middlewares/OperationEndpointResolverMiddleware.kt
+++ b/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/middlewares/OperationEndpointResolverMiddleware.kt
@@ -113,7 +113,16 @@ open class OperationEndpointResolverMiddleware(
                 }
         }
 
-        writer.openBlock("let endpointParamsBlock = { [config] (context: \$N) in", "}", SmithyTypes.Context) {
+        // Capture list is omitted when there are no client context params, to prevent a Swift "unused capture" warning.
+        // This primarily happens in protocol tests.
+        val hasClientContextParams = ctx.service.getTrait<ClientContextParamsTrait>()?.parameters?.isNotEmpty() ?: false
+        val captureList = "[config] ".takeIf { hasClientContextParams } ?: ""
+        writer.openBlock(
+            "let endpointParamsBlock = { \$L(context: \$N) in",
+            "}",
+            captureList,
+            SmithyTypes.Context,
+        ) {
             writer.write("EndpointParams(\$L)", params.joinToString(", "))
         }
     }
diff --git a/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/middlewares/providers/HttpHeaderProvider.kt b/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/middlewares/providers/HttpHeaderProvider.kt
index 84ea6369d..a6c88e298 100644
--- a/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/middlewares/providers/HttpHeaderProvider.kt
+++ b/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/middlewares/providers/HttpHeaderProvider.kt
@@ -180,6 +180,10 @@ class HttpHeaderProvider(
                 val mapValueShapeTargetSymbol = ctx.symbolProvider.toSymbol(mapValueShapeTarget)
 
                 writer.openBlock("for (prefixHeaderMapKey, prefixHeaderMapValue) in $memberName { ", "}") {
+                    // Don't write a prefix header over a specific header that was also written to this request.
+                    // See the HttpEmptyPrefixHeadersRequestClient protocol tests on the REST protocols.
+                    writer.write("guard !items.exists(name: \"$paramName\\(prefixHeaderMapKey)\") else { continue }")
+
                     if (mapValueShapeTarget is CollectionShape) {
                         writer.openBlock("prefixHeaderMapValue.forEach { headerValue in ", "}") {
                             if (mapValueShapeTargetSymbol.isBoxed()) {

From 9e930c8592a0c632776216d3336c108d8b1c753e Mon Sep 17 00:00:00 2001
From: Josh Elkins <jbelkins@amazon.com>
Date: Tue, 17 Jun 2025 15:35:37 -0500
Subject: [PATCH 3/3] Back out capture list change

---
 .../middlewares/OperationEndpointResolverMiddleware.kt    | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/middlewares/OperationEndpointResolverMiddleware.kt b/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/middlewares/OperationEndpointResolverMiddleware.kt
index aaeff3714..528ede514 100644
--- a/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/middlewares/OperationEndpointResolverMiddleware.kt
+++ b/smithy-swift-codegen/src/main/kotlin/software/amazon/smithy/swift/codegen/integration/middlewares/OperationEndpointResolverMiddleware.kt
@@ -112,15 +112,9 @@ open class OperationEndpointResolverMiddleware(
                     }
                 }
         }
-
-        // Capture list is omitted when there are no client context params, to prevent a Swift "unused capture" warning.
-        // This primarily happens in protocol tests.
-        val hasClientContextParams = ctx.service.getTrait<ClientContextParamsTrait>()?.parameters?.isNotEmpty() ?: false
-        val captureList = "[config] ".takeIf { hasClientContextParams } ?: ""
         writer.openBlock(
-            "let endpointParamsBlock = { \$L(context: \$N) in",
+            "let endpointParamsBlock = { [config] (context: \$N) in",
             "}",
-            captureList,
             SmithyTypes.Context,
         ) {
             writer.write("EndpointParams(\$L)", params.joinToString(", "))