Skip to content

Commit 48cd3a9

Browse files
authored
chore: fix AWS integrations and dependencies (#447)
This commit adds AWS runtime config integrations and fixes dependency management to match smithy-typescript. It also fixes an issue where the SymbolProvider decoration was not happening.
1 parent 94c21ba commit 48cd3a9

File tree

8 files changed

+254
-26
lines changed

8 files changed

+254
-26
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/*
2+
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.smithy.aws.typescript.codegen;
17+
18+
import java.util.logging.Logger;
19+
import software.amazon.smithy.aws.traits.ServiceTrait;
20+
import software.amazon.smithy.codegen.core.SymbolProvider;
21+
import software.amazon.smithy.model.Model;
22+
import software.amazon.smithy.model.shapes.ServiceShape;
23+
import software.amazon.smithy.typescript.codegen.LanguageTarget;
24+
import software.amazon.smithy.typescript.codegen.TypeScriptDependency;
25+
import software.amazon.smithy.typescript.codegen.TypeScriptSettings;
26+
import software.amazon.smithy.typescript.codegen.TypeScriptWriter;
27+
import software.amazon.smithy.typescript.codegen.integration.TypeScriptIntegration;
28+
29+
/**
30+
* AWS clients need to know the service name used to sign requests,
31+
* credentials for signing requests, and the region name used to resolve
32+
* endpoints.
33+
*
34+
* <p>This plugin adds the following config interface fields:
35+
*
36+
* <ul>
37+
* <li>signingName: Defines the service name that signs AWS requests.</li>
38+
* <li>credentialDefaultProvider: Provides credentials if no credentials
39+
* are explicitly provided.</li>
40+
* <li>regionDefaultProvider: Provides a region if no region is
41+
* explicitly provided</li>
42+
* </ul>
43+
*
44+
* <p>This plugin adds the following Node runtime specific values:
45+
*
46+
* <ul>
47+
* <li>signingName: Sets this to the signing name derived from the model.</li>
48+
* <li>credentialDefaultProvider: Uses the default credential provider that
49+
* checks things like environment variables and the AWS config file.</li>
50+
* <li>regionDefaultProvider: Uses the default region provider that
51+
* checks things like environment variables and the AWS config file.</li>
52+
* </ul>
53+
*
54+
* <p>This plugin adds the following Browser runtime specific values:
55+
*
56+
* <ul>
57+
* <li>signingName: Sets this to the signing name derived from the model.</li>
58+
* <li>credentialDefaultProvider: Throws an exception since credentials must
59+
* be explicitly provided in the browser (environment variables and
60+
* the shared config can't be resolved from the browser).</li>
61+
* <li>regionDefaultProvider: Throws an exception since a region must
62+
* be explicitly provided in the browser (environment variables and
63+
* the shared config can't be resolved from the browser).</li>
64+
* </ul>
65+
*/
66+
public final class AddAwsRuntimeConfig implements TypeScriptIntegration {
67+
68+
private static final Logger LOGGER = Logger.getLogger(AddAwsRuntimeConfig.class.getName());
69+
70+
@Override
71+
public void addConfigInterfaceFields(
72+
TypeScriptSettings settings,
73+
Model model,
74+
SymbolProvider symbolProvider,
75+
TypeScriptWriter writer
76+
) {
77+
writer.addImport("Provider", "__Provider", TypeScriptDependency.AWS_SDK_TYPES.packageName);
78+
writer.addImport("Credentials", "__Credentials", TypeScriptDependency.AWS_SDK_TYPES.packageName);
79+
80+
writer.writeDocs("The service name with which to sign requests.")
81+
.write("signingName?: string;\n");
82+
writer.writeDocs("Default credentials provider; Not available in browser runtime")
83+
.write("credentialDefaultProvider?: (input: any) => __Provider<__Credentials>;\n");
84+
writer.writeDocs("Provider function that return promise of a region string")
85+
.write("regionDefaultProvider?: (input: any) => __Provider<string>;\n");
86+
}
87+
88+
@Override
89+
public void addRuntimeConfigValues(
90+
TypeScriptSettings settings,
91+
Model model,
92+
SymbolProvider symbolProvider,
93+
TypeScriptWriter writer,
94+
LanguageTarget target
95+
) {
96+
ServiceShape service = settings.getService(model);
97+
String signingName = service.getTrait(ServiceTrait.class)
98+
.map(ServiceTrait::getArnNamespace)
99+
.orElse(null);
100+
101+
if (signingName != null) {
102+
writer.write("signingName: $S,", signingName);
103+
} else {
104+
LOGGER.info("Cannot generate a signing name for the client because no aws.api#Service "
105+
+ "trait was found on " + service.getId());
106+
}
107+
108+
switch (target) {
109+
case NODE:
110+
writeNodeConfig(writer);
111+
break;
112+
case BROWSER:
113+
writeBrowserConfig(writer);
114+
break;
115+
default:
116+
LOGGER.info("Unknown JavaScript target: " + target);
117+
}
118+
}
119+
120+
private void writeBrowserConfig(TypeScriptWriter writer) {
121+
writer.addDependency(TypeScriptDependency.INVALID_DEPENDENCY);
122+
writer.addImport("invalidFunction", "invalidFunction", TypeScriptDependency.INVALID_DEPENDENCY.packageName);
123+
writer.write("credentialDefaultProvider: invalidFunction(\"Credential is missing\") as any,");
124+
writer.write("regionDefaultProvider: invalidFunction(\"Region is missing\") as any,");
125+
}
126+
127+
private void writeNodeConfig(TypeScriptWriter writer) {
128+
writer.addDependency(AwsDependency.CREDENTIAL_PROVIDER_NODE);
129+
writer.addDependency(AwsDependency.REGION_PROVIDER);
130+
writer.addImport("defaultProvider", "credentialDefaultProvider",
131+
AwsDependency.CREDENTIAL_PROVIDER_NODE.packageName);
132+
writer.addImport("defaultProvider", "regionDefaultProvider", AwsDependency.REGION_PROVIDER.packageName);
133+
writer.write("credentialDefaultProvider,");
134+
writer.write("regionDefaultProvider,");
135+
}
136+
}

codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddBuiltinPlugins.java

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515

1616
package software.amazon.smithy.aws.typescript.codegen;
1717

18-
import static software.amazon.smithy.typescript.codegen.integration.RuntimeClientPlugin.Convention;
18+
import static software.amazon.smithy.typescript.codegen.integration.RuntimeClientPlugin.Convention.HAS_CONFIG;
19+
import static software.amazon.smithy.typescript.codegen.integration.RuntimeClientPlugin.Convention.HAS_MIDDLEWARE;
1920

2021
import java.util.List;
22+
import software.amazon.smithy.typescript.codegen.TypeScriptDependency;
2123
import software.amazon.smithy.typescript.codegen.integration.RuntimeClientPlugin;
2224
import software.amazon.smithy.typescript.codegen.integration.TypeScriptIntegration;
2325
import software.amazon.smithy.utils.ListUtils;
@@ -27,33 +29,29 @@
2729
*/
2830
public class AddBuiltinPlugins implements TypeScriptIntegration {
2931

30-
private static final String CONFIG_RESOLVER_VERSION = "^0.1.0-preview.5";
31-
3232
@Override
3333
public List<RuntimeClientPlugin> getClientPlugins() {
3434
// Note that order is significant because configurations might
3535
// rely on previously resolved values.
3636
return ListUtils.of(
3737
RuntimeClientPlugin.builder()
38-
.withConventions("@aws-sdk/config-resolver", CONFIG_RESOLVER_VERSION, "Region",
39-
Convention.HAS_CONFIG)
38+
.withConventions(TypeScriptDependency.CONFIG_RESOLVER.dependency, "Region", HAS_CONFIG)
4039
.build(),
4140
RuntimeClientPlugin.builder()
42-
.withConventions("@aws-sdk/middleware-signing", "^0.1.0-preview.7", "AwsAuth")
41+
.withConventions(AwsDependency.MIDDLEWARE_SIGNING.dependency, "AwsAuth")
4342
.build(),
4443
RuntimeClientPlugin.builder()
45-
.withConventions("@aws-sdk/config-resolver", CONFIG_RESOLVER_VERSION, "Endpoints",
46-
Convention.HAS_CONFIG)
44+
.withConventions(TypeScriptDependency.CONFIG_RESOLVER.dependency, "Endpoints", HAS_CONFIG)
4745
.build(),
4846
RuntimeClientPlugin.builder()
49-
.withConventions("@aws-sdk/middleware-retry", "^0.1.0-preview.5", "Retry")
47+
.withConventions(TypeScriptDependency.MIDDLEWARE_RETRY.dependency, "Retry")
5048
.build(),
5149
RuntimeClientPlugin.builder()
52-
.withConventions("@aws-sdk/middleware-user-agent", "^0.1.0-preview.1", "UserAgent")
50+
.withConventions(TypeScriptDependency.MIDDLEWARE_USER_AGENT.dependency, "UserAgent")
5351
.build(),
5452
RuntimeClientPlugin.builder()
55-
.withConventions("@aws-sdk/middleware-content-length", "^0.1.0-preview.5", "ContentLength",
56-
Convention.HAS_MIDDLEWARE)
53+
.withConventions(TypeScriptDependency.MIDDLEWARE_CONTENT_LENGTH.dependency, "ContentLength",
54+
HAS_MIDDLEWARE)
5755
.build()
5856
);
5957
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.smithy.aws.typescript.codegen;
17+
18+
import static software.amazon.smithy.typescript.codegen.TypeScriptDependency.NORMAL_DEPENDENCY;
19+
20+
import java.util.Collections;
21+
import java.util.List;
22+
import software.amazon.smithy.codegen.core.SymbolDependency;
23+
import software.amazon.smithy.codegen.core.SymbolDependencyContainer;
24+
25+
/**
26+
* This enum should define all TypeScript dependencies that are introduced by
27+
* this package.
28+
*/
29+
public enum AwsDependency implements SymbolDependencyContainer {
30+
31+
MIDDLEWARE_SIGNING(NORMAL_DEPENDENCY, "@aws-sdk/middleware-signing", "^0.1.0-preview.7"),
32+
CREDENTIAL_PROVIDER_NODE(NORMAL_DEPENDENCY, "@aws-sdk/credential-provider-node", "^0.1.0-preview.7"),
33+
REGION_PROVIDER(NORMAL_DEPENDENCY, "@aws-sdk/region-provider", "^0.1.0-preview.5");
34+
35+
public final String packageName;
36+
public final String version;
37+
public final SymbolDependency dependency;
38+
39+
AwsDependency(String type, String name, String version) {
40+
this.dependency = SymbolDependency.builder().dependencyType(type).packageName(name).version(version).build();
41+
this.packageName = name;
42+
this.version = version;
43+
}
44+
45+
@Override
46+
public List<SymbolDependency> getDependencies() {
47+
return Collections.singletonList(dependency);
48+
}
49+
}

codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AwsServiceIdIntegration.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717

1818
import java.util.logging.Logger;
1919
import software.amazon.smithy.aws.traits.ServiceTrait;
20-
import software.amazon.smithy.build.PluginContext;
2120
import software.amazon.smithy.codegen.core.Symbol;
2221
import software.amazon.smithy.codegen.core.SymbolProvider;
22+
import software.amazon.smithy.model.Model;
2323
import software.amazon.smithy.typescript.codegen.TypeScriptSettings;
2424
import software.amazon.smithy.typescript.codegen.integration.TypeScriptIntegration;
2525

@@ -33,9 +33,14 @@ public final class AwsServiceIdIntegration implements TypeScriptIntegration {
3333

3434
@Override
3535
public SymbolProvider decorateSymbolProvider(
36-
PluginContext context, TypeScriptSettings settings, SymbolProvider symbolProvider) {
36+
TypeScriptSettings settings, Model model, SymbolProvider symbolProvider) {
3737
return shape -> {
3838
Symbol symbol = symbolProvider.toSymbol(shape);
39+
40+
if (!shape.isServiceShape()) {
41+
return symbol;
42+
}
43+
3944
// If the SDK service ID trait is present, use that, otherwise fall back to
4045
// the default naming strategy for the service.
4146
return shape.getTrait(ServiceTrait.class)
@@ -49,11 +54,11 @@ public SymbolProvider decorateSymbolProvider(
4954
}
5055

5156
private static Symbol updateServiceSymbol(Symbol symbol, String serviceId) {
52-
String name = serviceId.replace(" ", "");
57+
String name = serviceId.replace(" ", "") + "Client";
5358
return symbol.toBuilder()
5459
.name(name)
55-
.namespace("./" + name + "Client", "/")
56-
.definitionFile(name + "Client.ts")
60+
.namespace("./" + name, "/")
61+
.definitionFile(name + ".ts")
5762
.build();
5863
}
5964
}
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
software.amazon.smithy.aws.typescript.codegen.AddAwsRuntimeConfig
12
software.amazon.smithy.aws.typescript.codegen.AddBuiltinPlugins
23
software.amazon.smithy.aws.typescript.codegen.AddProtocols
34
software.amazon.smithy.aws.typescript.codegen.AwsServiceIdIntegration
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package software.amazon.smithy.aws.typescript.codegen;
2+
3+
import static org.hamcrest.MatcherAssert.assertThat;
4+
import static org.hamcrest.Matchers.containsString;
5+
6+
import org.junit.jupiter.api.Test;
7+
import software.amazon.smithy.build.MockManifest;
8+
import software.amazon.smithy.build.PluginContext;
9+
import software.amazon.smithy.model.Model;
10+
import software.amazon.smithy.model.node.Node;
11+
import software.amazon.smithy.typescript.codegen.TypeScriptCodegenPlugin;
12+
13+
public class AddAwsRuntimeConfigTest {
14+
@Test
15+
public void addsAwsRuntimeConfigSettings() {
16+
Model model = Model.assembler()
17+
.addImport(getClass().getResource("serviceid.smithy"))
18+
.discoverModels()
19+
.assemble()
20+
.unwrap();
21+
MockManifest manifest = new MockManifest();
22+
PluginContext context = PluginContext.builder()
23+
.pluginClassLoader(getClass().getClassLoader())
24+
.model(model)
25+
.fileManifest(manifest)
26+
.settings(Node.objectNodeBuilder()
27+
.withMember("service", Node.from("smithy.example#OriginalName"))
28+
.withMember("package", Node.from("example"))
29+
.withMember("packageVersion", Node.from("1.0.0"))
30+
.build())
31+
.build();
32+
new TypeScriptCodegenPlugin().execute(context);
33+
34+
// Check that one of the many dependencies was added.
35+
assertThat(manifest.getFileString("package.json").get(),
36+
containsString(AwsDependency.CREDENTIAL_PROVIDER_NODE.packageName));
37+
38+
// Check that both the config files were updated.
39+
assertThat(manifest.getFileString("runtimeConfig.ts").get(), containsString("credentialDefaultProvider"));
40+
assertThat(manifest.getFileString("runtimeConfig.browser.ts").get(), containsString("invalidFunction"));
41+
42+
// Check that the dependency interface was updated.
43+
assertThat(manifest.getFileString("NotSameClient.ts").get(), containsString("credentialDefaultProvider?"));
44+
}
45+
}

codegen/smithy-aws-typescript-codegen/src/test/java/software/amazon/smithy/aws/typescript/codegen/AwsServiceIdIntegrationTest.java

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@
77
import static org.hamcrest.Matchers.equalTo;
88

99
import org.junit.jupiter.api.Test;
10-
import software.amazon.smithy.build.MockManifest;
11-
import software.amazon.smithy.build.PluginContext;
1210
import software.amazon.smithy.codegen.core.Symbol;
1311
import software.amazon.smithy.codegen.core.SymbolProvider;
1412
import software.amazon.smithy.model.Model;
@@ -29,15 +27,10 @@ public void testSomeLibraryMethod() {
2927
AwsServiceIdIntegration integration = new AwsServiceIdIntegration();
3028
SymbolProvider provider = TypeScriptCodegenPlugin.createSymbolProvider(model);
3129
SymbolProvider decorated = integration.decorateSymbolProvider(
32-
PluginContext.builder()
33-
.model(model)
34-
.fileManifest(new MockManifest())
35-
.build(),
36-
new TypeScriptSettings(),
37-
provider);
30+
new TypeScriptSettings(), model, provider);
3831
Symbol symbol = decorated.toSymbol(service);
3932

40-
assertThat(symbol.getName(), equalTo("NotSame"));
33+
assertThat(symbol.getName(), equalTo("NotSameClient"));
4134
assertThat(symbol.getNamespace(), equalTo("./NotSameClient"));
4235
assertThat(symbol.getDefinitionFile(), equalTo("NotSameClient.ts"));
4336
}
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
namespace smithy.example
22

33
@aws.api#service(sdkId: "Not Same")
4+
@protocols([{name: "aws.rest-json-1.1"}])
45
service OriginalName {
56
version: "2019-10-15",
67
}

0 commit comments

Comments
 (0)