From dcf2b9c95c1f66967538d04f624897c075471e37 Mon Sep 17 00:00:00 2001
From: Steven Yuan <yuasteve@amazon.com>
Date: Tue, 21 Nov 2023 14:27:27 -0800
Subject: [PATCH 1/4] feat(experimentalIdentityAndAuth): update
 `ConfigField::configFieldWriter()`

---
 .../codegen/auth/http/ConfigField.java        | 11 +---
 .../integration/AddHttpAuthSchemePlugin.java  | 58 ++++++++++---------
 2 files changed, 33 insertions(+), 36 deletions(-)

diff --git a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/auth/http/ConfigField.java b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/auth/http/ConfigField.java
index e10d0515b85..50a53478544 100644
--- a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/auth/http/ConfigField.java
+++ b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/auth/http/ConfigField.java
@@ -33,7 +33,7 @@ public final record ConfigField(
     Type type,
     Symbol inputType,
     Symbol resolvedType,
-    BiConsumer<TypeScriptWriter, ConfigField> configFieldWriter,
+    Optional<BiConsumer<TypeScriptWriter, ConfigField>> configFieldWriter,
     Optional<Consumer<TypeScriptWriter>> docs
 ) implements ToSmithyBuilder<ConfigField> {
 
@@ -63,7 +63,7 @@ public Builder toBuilder() {
             .type(type)
             .inputType(inputType)
             .resolvedType(resolvedType)
-            .configFieldWriter(configFieldWriter)
+            .configFieldWriter(configFieldWriter.orElse(null))
             .docs(docs.orElse(null));
     }
 
@@ -77,17 +77,12 @@ public static final class Builder implements SmithyBuilder<ConfigField> {
 
         @Override
         public ConfigField build() {
-            if (configFieldWriter == null) {
-                configFieldWriter = type.equals(Type.MAIN)
-                    ? ConfigField::defaultMainConfigFieldWriter
-                    : ConfigField::defaultAuxiliaryConfigFieldWriter;
-            }
             return new ConfigField(
                 SmithyBuilder.requiredState("name", name),
                 SmithyBuilder.requiredState("type", type),
                 SmithyBuilder.requiredState("inputType", inputType),
                 SmithyBuilder.requiredState("resolvedType", resolvedType),
-                SmithyBuilder.requiredState("configFieldWriter", configFieldWriter),
+                Optional.ofNullable(configFieldWriter),
                 Optional.ofNullable(docs));
         }
 
diff --git a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/auth/http/integration/AddHttpAuthSchemePlugin.java b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/auth/http/integration/AddHttpAuthSchemePlugin.java
index 81e7a3926aa..877fab66d01 100644
--- a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/auth/http/integration/AddHttpAuthSchemePlugin.java
+++ b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/auth/http/integration/AddHttpAuthSchemePlugin.java
@@ -9,6 +9,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 import software.amazon.smithy.codegen.core.CodegenException;
 import software.amazon.smithy.codegen.core.Symbol;
 import software.amazon.smithy.model.knowledge.ServiceIndex;
@@ -286,8 +287,10 @@ private void generateHttpAuthSchemeInputConfigInterface(
         w.write("httpAuthSchemeProvider?: $L;\n", httpAuthSchemeProviderName);
 
         for (ConfigField configField : configFields.values()) {
-            configField.docs().ifPresent(docs -> w.writeDocs(() -> w.write("$C", docs)));
-            w.write("$L?: $T;", configField.name(), configField.inputType());
+            if (configField.configFieldWriter().isPresent()) {
+                configField.docs().ifPresent(docs -> w.writeDocs(() -> w.write("$C", docs)));
+                w.write("$L?: $T;", configField.name(), configField.inputType());
+            }
         }
         w.dedent();
         w.write("}\n");
@@ -349,8 +352,10 @@ private void generateHttpAuthSchemeResolvedConfigInterface(
             @internal""");
         w.write("readonly httpAuthSchemeProvider: $L;\n", httpAuthSchemeProviderName);
         for (ConfigField configField : configFields.values()) {
-            configField.docs().ifPresent(docs -> w.writeDocs(() -> w.write("$C", docs)));
-            w.write("readonly $L?: $T;", configField.name(), configField.resolvedType());
+            if (configField.configFieldWriter().isPresent()) {
+                configField.docs().ifPresent(docs -> w.writeDocs(() -> w.write("$C", docs)));
+                w.write("readonly $L?: $T;", configField.name(), configField.resolvedType());
+            }
         }
         w.dedent();
         w.write("}\n");
@@ -379,33 +384,23 @@ private void generateResolveHttpAuthSchemeConfigFunction(
         w.pushState(s);
         Map<String, ConfigField> configFields = s.getConfigFields();
         Map<Symbol, ResolveConfigFunction> resolveConfigFunctions = s.getResolveConfigFunctions();
+        Map<Symbol, ResolveConfigFunction> previousResolvedFunctions = resolveConfigFunctions.entrySet().stream()
+            .filter(e -> e.getValue().previouslyResolved().isPresent())
+            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
         w.writeDocs("@internal");
         w.writeInline("export const resolveHttpAuthSchemeConfig = <T>(config: T & HttpAuthSchemeInputConfig");
-        if (!resolveConfigFunctions.isEmpty()) {
-            w.writeInline(" & ");
-            Iterator<ResolveConfigFunction> iter = resolveConfigFunctions.values().iterator();
-            while (iter.hasNext()) {
-                ResolveConfigFunction entry = iter.next();
-                w.writeInline("$T", entry.inputConfig());
-                entry.previouslyResolved().ifPresent(p -> w.writeInline(" & $T", p));
-                if (iter.hasNext()) {
-                    w.writeInline(" & ");
-                }
-            }
-        }
-        w.writeInline("): T & HttpAuthSchemeResolvedConfig");
-        if (!resolveConfigFunctions.isEmpty()) {
+        if (!previousResolvedFunctions.isEmpty()) {
             w.writeInline(" & ");
-            Iterator<ResolveConfigFunction> iter = resolveConfigFunctions.values().iterator();
+            Iterator<ResolveConfigFunction> iter = previousResolvedFunctions.values().iterator();
             while (iter.hasNext()) {
                 ResolveConfigFunction entry = iter.next();
-                w.writeInline("$T", entry.resolvedConfig());
+                w.writeInline("$T", entry.previouslyResolved().get());
                 if (iter.hasNext()) {
                     w.writeInline(" & ");
                 }
             }
         }
-        w.write(" => {");
+        w.write("): T & HttpAuthSchemeResolvedConfig => {");
         w.indent();
         w.pushState(ResolveHttpAuthSchemeConfigFunctionConfigFieldsCodeSection.builder()
             .service(s.getService())
@@ -417,7 +412,7 @@ private void generateResolveHttpAuthSchemeConfigFunction(
             .build());
         w.addDependency(TypeScriptDependency.SMITHY_CORE);
         for (ConfigField configField : configFields.values()) {
-            configField.configFieldWriter().accept(w, configField);
+            configField.configFieldWriter().ifPresent(cfw -> cfw.accept(w, configField));
         }
         w.popState();
         w.pushState(ResolveHttpAuthSchemeConfigFunctionReturnBlockCodeSection.builder()
@@ -428,16 +423,23 @@ private void generateResolveHttpAuthSchemeConfigFunction(
             .integrations(s.getIntegrations())
             .configFields(configFields)
             .build());
-
+        Integer i = 0;
+        String configName = "config";
         for (ResolveConfigFunction resolveConfigFunction : resolveConfigFunctions.values()) {
-            w.write("config = $T(config);", resolveConfigFunction.resolveConfigFunction());
+            w.write("const config_$L = $T($L);", i, resolveConfigFunction.resolveConfigFunction(), configName);
+            configName = "config_" + i;
+            i++;
         }
-        w.openBlock("return {", "} as T & HttpAuthSchemeResolvedConfig;", () -> {
-            w.write("...config,");
-            for (ConfigField configField : configFields.values()) {
+        w.write("return {");
+        w.indent();
+        w.write("...$L,", configName);
+        for (ConfigField configField : configFields.values()) {
+            if (configField.configFieldWriter().isPresent()) {
                 w.write("$L,", configField.name());
             }
-        });
+        }
+        w.dedent();
+        w.write("} as T & HttpAuthSchemeResolvedConfig;");
         w.popState();
         w.dedent();
         w.write("};");

From ff9bbf31ead1918e5d44342c26b508e86da56533 Mon Sep 17 00:00:00 2001
From: Steven Yuan <yuasteve@amazon.com>
Date: Tue, 21 Nov 2023 21:19:51 -0800
Subject: [PATCH 2/4] fix(experimentalIdentityAndAuth): fix
 `HttpAuthSchemeParametersInterfaceCodeSection` usage

---
 .../codegen/auth/http/HttpAuthSchemeProviderGenerator.java    | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/auth/http/HttpAuthSchemeProviderGenerator.java b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/auth/http/HttpAuthSchemeProviderGenerator.java
index 0219317e458..7c6b4b86c41 100644
--- a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/auth/http/HttpAuthSchemeProviderGenerator.java
+++ b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/auth/http/HttpAuthSchemeProviderGenerator.java
@@ -31,6 +31,7 @@
 import software.amazon.smithy.typescript.codegen.auth.http.sections.DefaultHttpAuthSchemeProviderFunctionCodeSection;
 import software.amazon.smithy.typescript.codegen.auth.http.sections.HttpAuthOptionFunctionCodeSection;
 import software.amazon.smithy.typescript.codegen.auth.http.sections.HttpAuthOptionFunctionsCodeSection;
+import software.amazon.smithy.typescript.codegen.auth.http.sections.HttpAuthSchemeParametersInterfaceCodeSection;
 import software.amazon.smithy.typescript.codegen.auth.http.sections.HttpAuthSchemeParametersProviderInterfaceCodeSection;
 import software.amazon.smithy.typescript.codegen.auth.http.sections.HttpAuthSchemeProviderInterfaceCodeSection;
 import software.amazon.smithy.typescript.codegen.integration.TypeScriptIntegration;
@@ -116,11 +117,12 @@ export interface WeatherHttpAuthSchemeParameters extends HttpAuthSchemeParameter
     */
     private void generateHttpAuthSchemeParametersInterface() {
         delegator.useFileWriter(AuthUtils.HTTP_AUTH_SCHEME_PROVIDER_PATH, w -> {
-            w.pushState(HttpAuthSchemeProviderInterfaceCodeSection.builder()
+            w.pushState(HttpAuthSchemeParametersInterfaceCodeSection.builder()
                 .service(serviceShape)
                 .settings(settings)
                 .model(model)
                 .symbolProvider(symbolProvider)
+                .httpAuthSchemeParameters(httpAuthSchemeParameters)
                 .build());
             w.addDependency(TypeScriptDependency.SMITHY_TYPES);
             w.addImport("HttpAuthSchemeParameters", null, TypeScriptDependency.SMITHY_TYPES);

From 6fa2a177b001114ecc4565c41bb6cdf4573384aa Mon Sep 17 00:00:00 2001
From: Steven Yuan <yuasteve@amazon.com>
Date: Tue, 21 Nov 2023 21:35:39 -0800
Subject: [PATCH 3/4] feat(experimentalIdentityAndAuth): make
 `normalizeAuthSchemeName()` public

---
 .../codegen/auth/http/HttpAuthSchemeProviderGenerator.java      | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/auth/http/HttpAuthSchemeProviderGenerator.java b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/auth/http/HttpAuthSchemeProviderGenerator.java
index 7c6b4b86c41..402923e1d98 100644
--- a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/auth/http/HttpAuthSchemeProviderGenerator.java
+++ b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/auth/http/HttpAuthSchemeProviderGenerator.java
@@ -330,7 +330,7 @@ private void generateHttpAuthOptionFunction(
         w.popState();
     }
 
-    private static String normalizeAuthSchemeName(ShapeId shapeId) {
+    public static String normalizeAuthSchemeName(ShapeId shapeId) {
         return String.join("", Arrays
             .asList(shapeId.toString().split("[.#]"))
             .stream().map(StringUtils::capitalize)

From c567fb2a32fc606eb6327d3a01ee2f5a59ac2acd Mon Sep 17 00:00:00 2001
From: Steven Yuan <yuasteve@amazon.com>
Date: Tue, 21 Nov 2023 21:45:01 -0800
Subject: [PATCH 4/4] fix(experimentalIdentityAndAuth): update
 `DefaultIdentityProviderConfig` to not dedupe

---
 .../integration/AddHttpAuthSchemePlugin.java  | 25 +++----------------
 1 file changed, 4 insertions(+), 21 deletions(-)

diff --git a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/auth/http/integration/AddHttpAuthSchemePlugin.java b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/auth/http/integration/AddHttpAuthSchemePlugin.java
index 877fab66d01..64dd18feec6 100644
--- a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/auth/http/integration/AddHttpAuthSchemePlugin.java
+++ b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/auth/http/integration/AddHttpAuthSchemePlugin.java
@@ -5,12 +5,10 @@
 
 package software.amazon.smithy.typescript.codegen.auth.http.integration;
 
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
-import software.amazon.smithy.codegen.core.CodegenException;
 import software.amazon.smithy.codegen.core.Symbol;
 import software.amazon.smithy.model.knowledge.ServiceIndex;
 import software.amazon.smithy.model.shapes.ServiceShape;
@@ -147,30 +145,15 @@ private getIdentityProviderConfigProvider() {
                         s.getModel(),
                         s.getSettings());
                     ServiceIndex serviceIndex = ServiceIndex.of(s.getModel());
-                    Map<ShapeId, HttpAuthScheme> httpAuthSchemes
-                        = AuthUtils.getAllEffectiveNoAuthAwareAuthSchemes(s.getService(), serviceIndex, authIndex);
-                    // TODO(experimentalIdentityAndAuth): figure out a better deduping strategy
-                    Map<String, ConfigField> visitedConfigFields = new HashMap<>();
+                    Map<ShapeId, HttpAuthScheme> httpAuthSchemes =
+                        AuthUtils.getAllEffectiveNoAuthAwareAuthSchemes(s.getService(), serviceIndex, authIndex);
                     for (HttpAuthScheme scheme : httpAuthSchemes.values()) {
                         if (scheme == null) {
                             continue;
                         }
                         for (ConfigField configField : scheme.getConfigFields()) {
-                            if (visitedConfigFields.containsKey(configField.name())) {
-                                ConfigField visitedConfigField = visitedConfigFields.get(configField.name());
-                                if (!configField.equals(visitedConfigField)) {
-                                    throw new CodegenException("Contradicting `ConfigField` definitions for `"
-                                        + configField.name()
-                                        + "`; existing: "
-                                        + visitedConfigField
-                                        + ", conflict: "
-                                        + configField);
-                                }
-                            } else {
-                                visitedConfigFields.put(configField.name(), configField);
-                                if (configField.type().equals(ConfigField.Type.MAIN)) {
-                                    w.write("$S: config.$L,", scheme.getSchemeId().toString(), configField.name());
-                                }
+                            if (configField.type().equals(ConfigField.Type.MAIN)) {
+                                w.write("$S: config.$L,", scheme.getSchemeId().toString(), configField.name());
                             }
                         }
                     }