Skip to content

Commit

Permalink
feat(experimentalIdentityAndAuth): add collect*() methods to dedupe…
Browse files Browse the repository at this point in the history
… `ConfigField`s and `HttpAuthSchemeParameter` (#948)
  • Loading branch information
Steven Yuan authored Sep 20, 2023
1 parent 4cc46d5 commit bc80da4
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 71 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,15 @@
import software.amazon.smithy.codegen.core.SymbolProvider;
import software.amazon.smithy.codegen.core.SymbolReference;
import software.amazon.smithy.model.Model;
import software.amazon.smithy.model.knowledge.ServiceIndex;
import software.amazon.smithy.model.knowledge.TopDownIndex;
import software.amazon.smithy.model.shapes.OperationShape;
import software.amazon.smithy.model.shapes.ServiceShape;
import software.amazon.smithy.model.shapes.ShapeId;
import software.amazon.smithy.rulesengine.traits.EndpointRuleSetTrait;
import software.amazon.smithy.typescript.codegen.auth.AuthUtils;
import software.amazon.smithy.typescript.codegen.auth.http.integration.HttpAuthTypeScriptIntegration;
import software.amazon.smithy.typescript.codegen.auth.http.HttpAuthScheme;
import software.amazon.smithy.typescript.codegen.auth.http.SupportedHttpAuthSchemesIndex;
import software.amazon.smithy.typescript.codegen.endpointsV2.EndpointsV2Generator;
import software.amazon.smithy.typescript.codegen.integration.RuntimeClientPlugin;
import software.amazon.smithy.typescript.codegen.integration.TypeScriptIntegration;
Expand Down Expand Up @@ -329,20 +332,18 @@ private void generateClientDefaults() {
// Write custom configuration dependencies.
for (TypeScriptIntegration integration : integrations) {
integration.addConfigInterfaceFields(settings, model, symbolProvider, writer);
// feat(experimentalIdentityAndAuth): write any HttpAuthScheme config fields into ClientDefaults
// WARNING: may be changed later in lieu of {@link TypeScriptIntegration#addConfigInterfaceFields()},
// but will depend after HttpAuthScheme integration implementations.
if (settings.getExperimentalIdentityAndAuth()) {
if (!(integration instanceof HttpAuthTypeScriptIntegration)) {
continue;
}
HttpAuthTypeScriptIntegration httpAuthIntegration = (HttpAuthTypeScriptIntegration) integration;
httpAuthIntegration.getHttpAuthScheme().ifPresent(authScheme -> {
for (ConfigField configField : authScheme.getConfigFields()) {
writer.writeDocs(() -> writer.write("$C", configField.docs()));
writer.write("$L?: $C;\n", configField.name(), configField.inputType());
}
});
}

// feat(experimentalIdentityAndAuth): write any HttpAuthScheme config fields into ClientDefaults
// WARNING: may be changed later in lieu of {@link TypeScriptIntegration#addConfigInterfaceFields()},
// but will depend after HttpAuthScheme integration implementations.
if (settings.getExperimentalIdentityAndAuth()) {
Map<ShapeId, HttpAuthScheme> httpAuthSchemes = AuthUtils.getAllEffectiveNoAuthAwareAuthSchemes(
service, ServiceIndex.of(model), new SupportedHttpAuthSchemesIndex(integrations));
Map<String, ConfigField> configFields = AuthUtils.collectConfigFields(httpAuthSchemes.values());
for (ConfigField configField : configFields.values()) {
writer.writeDocs(() -> writer.write("$C", configField.docs()));
writer.write("$L?: $C;\n", configField.name(), configField.inputType());
}
}
}).write("");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,23 @@
package software.amazon.smithy.typescript.codegen.auth;

import java.nio.file.Paths;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import software.amazon.smithy.codegen.core.CodegenException;
import software.amazon.smithy.codegen.core.SymbolDependency;
import software.amazon.smithy.model.knowledge.ServiceIndex;
import software.amazon.smithy.model.knowledge.ServiceIndex.AuthSchemeMode;
import software.amazon.smithy.model.shapes.ServiceShape;
import software.amazon.smithy.model.shapes.ShapeId;
import software.amazon.smithy.typescript.codegen.CodegenUtils;
import software.amazon.smithy.typescript.codegen.ConfigField;
import software.amazon.smithy.typescript.codegen.Dependency;
import software.amazon.smithy.typescript.codegen.auth.http.HttpAuthScheme;
import software.amazon.smithy.typescript.codegen.auth.http.HttpAuthSchemeParameter;
import software.amazon.smithy.typescript.codegen.auth.http.SupportedHttpAuthSchemesIndex;
import software.amazon.smithy.utils.SmithyInternalApi;

Expand Down Expand Up @@ -93,4 +98,55 @@ public static Map<ShapeId, HttpAuthScheme> getAllEffectiveNoAuthAwareAuthSchemes
// END
return effectiveAuthSchemes;
}

public static Map<String, ConfigField> collectConfigFields(Collection<HttpAuthScheme> httpAuthSchemes) {
Map<String, ConfigField> configFields = new HashMap<>();
for (HttpAuthScheme authScheme : httpAuthSchemes) {
if (authScheme == null) {
continue;
}
for (ConfigField configField : authScheme.getConfigFields()) {
if (configFields.containsKey(configField.name())) {
ConfigField existingConfigField = configFields.get(configField.name());
if (!configField.equals(existingConfigField)) {
throw new CodegenException("Contradicting `ConfigField` defintions for `"
+ configField.name()
+ "`; existing: "
+ existingConfigField
+ ", conflict: "
+ configField);
}
} else {
configFields.put(configField.name(), configField);
}
}
}
return configFields;
}

public static Map<String, HttpAuthSchemeParameter> collectHttpAuthSchemeParameters(
Collection<HttpAuthScheme> httpAuthSchemes) {
Map<String, HttpAuthSchemeParameter> httpAuthSchemeParameters = new HashMap<>();
for (HttpAuthScheme authScheme : httpAuthSchemes) {
if (authScheme == null) {
continue;
}
for (HttpAuthSchemeParameter param : authScheme.getHttpAuthSchemeParameters()) {
if (httpAuthSchemeParameters.containsKey(param.name())) {
HttpAuthSchemeParameter existingParam = httpAuthSchemeParameters.get(param.name());
if (!param.equals(existingParam)) {
throw new CodegenException("Contradicting `HttpAuthSchemeParameter` defintions for `"
+ param.name()
+ "`; existing: "
+ existingParam
+ ", conflict: "
+ param);
}
} else {
httpAuthSchemeParameters.put(param.name(), param);
}
}
}
return httpAuthSchemeParameters;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public class HttpAuthSchemeProviderGenerator implements Runnable {
private final ServiceShape serviceShape;
private final Symbol serviceSymbol;
private final String serviceName;
private final Map<String, HttpAuthSchemeParameter> httpAuthSchemeParameters;

/**
* Create an HttpAuthSchemeProviderGenerator.
Expand All @@ -73,6 +74,8 @@ public HttpAuthSchemeProviderGenerator(
this.serviceShape = settings.getService(model);
this.serviceSymbol = symbolProvider.toSymbol(serviceShape);
this.serviceName = CodegenUtils.getServiceName(settings, model, symbolProvider);
this.httpAuthSchemeParameters =
AuthUtils.collectHttpAuthSchemeParameters(authIndex.getSupportedHttpAuthSchemes().values());
}

@Override
Expand Down Expand Up @@ -103,10 +106,8 @@ private void generateHttpAuthSchemeParametersInterface() {
export interface $LHttpAuthSchemeParameters extends HttpAuthSchemeParameters {""", "}",
serviceName,
() -> {
for (HttpAuthScheme authScheme : authIndex.getSupportedHttpAuthSchemes().values()) {
for (HttpAuthSchemeParameter parameter : authScheme.getHttpAuthSchemeParameters()) {
w.write("$L?: $C;", parameter.name(), parameter.type());
}
for (HttpAuthSchemeParameter parameter : httpAuthSchemeParameters.values()) {
w.write("$L?: $C;", parameter.name(), parameter.type());
}
});
});
Expand Down Expand Up @@ -145,10 +146,8 @@ private void generateDefaultHttpAuthSchemeParametersProviderFunction() {
() -> {
w.openBlock("return {", "};", () -> {
w.write("operation: getSmithyContext(context).operation as string,");
for (HttpAuthScheme authScheme : authIndex.getSupportedHttpAuthSchemes().values()) {
for (HttpAuthSchemeParameter parameter : authScheme.getHttpAuthSchemeParameters()) {
w.write("$L: $C,", parameter.name(), parameter.source());
}
for (HttpAuthSchemeParameter parameter : httpAuthSchemeParameters.values()) {
w.write("$L: $C,", parameter.name(), parameter.source());
}
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,15 +59,16 @@ public void customize(TypeScriptCodegenContext codegenContext) {
ServiceShape serviceShape = codegenContext.settings().getService(codegenContext.model());
Map<ShapeId, HttpAuthScheme> effectiveAuthSchemes =
AuthUtils.getAllEffectiveNoAuthAwareAuthSchemes(serviceShape, serviceIndex, authIndex);
Map<String, ConfigField> configFields = AuthUtils.collectConfigFields(effectiveAuthSchemes.values());

generateHttpAuthExtensionConfigurationInterface(
delegator, effectiveAuthSchemes, serviceName);
delegator, configFields, serviceName);
generateHttpAuthExtensionRuntimeConfigType(
delegator, effectiveAuthSchemes, serviceName);
delegator, configFields, serviceName);
generateGetHttpAuthExtensionConfigurationFunction(
delegator, effectiveAuthSchemes, serviceName);
delegator, configFields, serviceName);
generateResolveHttpAuthRuntimeConfigFunction(
delegator, effectiveAuthSchemes, serviceName);
delegator, configFields, serviceName);
}

/*
Expand Down Expand Up @@ -109,7 +110,7 @@ export interface HttpAuthExtensionConfiguration {
*/
private void generateHttpAuthExtensionConfigurationInterface(
TypeScriptDelegator delegator,
Map<ShapeId, HttpAuthScheme> effectiveAuthSchemes,
Map<String, ConfigField> configFields,
String serviceName
) {
delegator.useFileWriter(AuthUtils.HTTP_AUTH_SCHEME_EXTENSION_PATH, w -> {
Expand All @@ -130,14 +131,8 @@ export interface HttpAuthExtensionConfiguration {""", "}",
serviceName);
w.write("httpAuthSchemeProvider(): $LHttpAuthSchemeProvider;", serviceName);

for (HttpAuthScheme authScheme : effectiveAuthSchemes.values()) {
if (authScheme == null) {
continue;
}
for (ConfigField configField : authScheme.getConfigFields()) {
if (!configField.type().equals(ConfigField.Type.MAIN)) {
continue;
}
for (ConfigField configField : configFields.values()) {
if (configField.type().equals(ConfigField.Type.MAIN)) {
String capitalizedName = StringUtils.capitalize(configField.name());
w.write("set$L($L: $C): void;", capitalizedName, configField.name(), configField.inputType());
w.write("$L(): $C | undefined;", configField.name(), configField.inputType());
Expand Down Expand Up @@ -177,7 +172,7 @@ export interface HttpAuthExtensionConfiguration {""", "}",
*/
private void generateHttpAuthExtensionRuntimeConfigType(
TypeScriptDelegator delegator,
Map<ShapeId, HttpAuthScheme> effectiveAuthSchemes,
Map<String, ConfigField> configFields,
String serviceName
) {
delegator.useFileWriter(AuthUtils.HTTP_AUTH_SCHEME_EXTENSION_PATH, w -> {
Expand All @@ -193,14 +188,8 @@ private void generateHttpAuthExtensionRuntimeConfigType(
w.write("httpAuthSchemes: HttpAuthScheme[];");
w.addImport(serviceName + "HttpAuthSchemeProvider", null, AuthUtils.AUTH_HTTP_PROVIDER_DEPENDENCY);
w.write("httpAuthSchemeProvider: $LHttpAuthSchemeProvider;", serviceName);
for (HttpAuthScheme authScheme : effectiveAuthSchemes.values()) {
if (authScheme == null) {
continue;
}
for (ConfigField configField : authScheme.getConfigFields()) {
if (!configField.type().equals(ConfigField.Type.MAIN)) {
continue;
}
for (ConfigField configField : configFields.values()) {
if (configField.type().equals(ConfigField.Type.MAIN)) {
w.write("$L: $C;", configField.name(), configField.inputType());
}
}
Expand Down Expand Up @@ -269,7 +258,7 @@ private void generateHttpAuthExtensionRuntimeConfigType(
*/
private void generateGetHttpAuthExtensionConfigurationFunction(
TypeScriptDelegator delegator,
Map<ShapeId, HttpAuthScheme> effectiveAuthSchemes,
Map<String, ConfigField> configFields,
String serviceName
) {
delegator.useFileWriter(AuthUtils.HTTP_AUTH_SCHEME_EXTENSION_PATH, w -> {
Expand All @@ -286,14 +275,8 @@ private void generateGetHttpAuthExtensionConfigurationFunction(
w.write("let _httpAuthSchemes = runtimeConfig.httpAuthSchemes!;");
w.addImport(serviceName + "HttpAuthSchemeProvider", null, AuthUtils.AUTH_HTTP_PROVIDER_DEPENDENCY);
w.write("let _httpAuthSchemeProvider = runtimeConfig.httpAuthSchemeProvider!;");
for (HttpAuthScheme authScheme : effectiveAuthSchemes.values()) {
if (authScheme == null) {
continue;
}
for (ConfigField configField : authScheme.getConfigFields()) {
if (!configField.type().equals(ConfigField.Type.MAIN)) {
continue;
}
for (ConfigField configField : configFields.values()) {
if (configField.type().equals(ConfigField.Type.MAIN)) {
w.write("let _$L = runtimeConfig.$L;", configField.name(), configField.name());
}
}
Expand All @@ -314,14 +297,8 @@ private void generateGetHttpAuthExtensionConfigurationFunction(
httpAuthSchemeProvider(): $LHttpAuthSchemeProvider {
return _httpAuthSchemeProvider;
},""", serviceName, serviceName);
for (HttpAuthScheme authScheme : effectiveAuthSchemes.values()) {
if (authScheme == null) {
continue;
}
for (ConfigField configField : authScheme.getConfigFields()) {
if (!configField.type().equals(ConfigField.Type.MAIN)) {
continue;
}
for (ConfigField configField : configFields.values()) {
if (configField.type().equals(ConfigField.Type.MAIN)) {
String capitalizedName = StringUtils.capitalize(configField.name());
w.write("""
set$L($L: $C): void {
Expand Down Expand Up @@ -356,7 +333,7 @@ private void generateGetHttpAuthExtensionConfigurationFunction(
*/
private void generateResolveHttpAuthRuntimeConfigFunction(
TypeScriptDelegator delegator,
Map<ShapeId, HttpAuthScheme> effectiveAuthSchemes,
Map<String, ConfigField> configFields,
String serviceName
) {
delegator.useFileWriter(AuthUtils.HTTP_AUTH_SCHEME_EXTENSION_PATH, w -> {
Expand All @@ -370,14 +347,8 @@ private void generateResolveHttpAuthRuntimeConfigFunction(
w.openBlock("return {", "};", () -> {
w.write("httpAuthSchemes: config.httpAuthSchemes(),");
w.write("httpAuthSchemeProvider: config.httpAuthSchemeProvider(),");
for (HttpAuthScheme authScheme : effectiveAuthSchemes.values()) {
if (authScheme == null) {
continue;
}
for (ConfigField configField : authScheme.getConfigFields()) {
if (!configField.type().equals(ConfigField.Type.MAIN)) {
continue;
}
for (ConfigField configField : configFields.values()) {
if (configField.type().equals(ConfigField.Type.MAIN)) {
w.write("$L: config.$L(),", configField.name(), configField.name());
}
}
Expand Down

0 comments on commit bc80da4

Please sign in to comment.