15
15
16
16
package software .amazon .smithy .aws .typescript .codegen ;
17
17
18
+ import java .util .ArrayList ;
19
+ import java .util .Collections ;
18
20
import java .util .List ;
19
21
import java .util .Map ;
20
22
import java .util .Optional ;
24
26
import software .amazon .smithy .aws .traits .ServiceTrait ;
25
27
import software .amazon .smithy .aws .traits .auth .SigV4Trait ;
26
28
import software .amazon .smithy .codegen .core .CodegenException ;
29
+ import software .amazon .smithy .model .node .ArrayNode ;
27
30
import software .amazon .smithy .model .node .Node ;
28
31
import software .amazon .smithy .model .node .ObjectNode ;
29
32
import software .amazon .smithy .model .node .StringNode ;
30
33
import software .amazon .smithy .model .shapes .ServiceShape ;
31
34
import software .amazon .smithy .typescript .codegen .TypeScriptDependency ;
32
35
import software .amazon .smithy .typescript .codegen .TypeScriptWriter ;
33
36
import software .amazon .smithy .utils .IoUtils ;
34
- import software .amazon .smithy .utils .OptionalUtils ;
35
37
import software .amazon .smithy .utils .SmithyInternalApi ;
36
38
37
39
/**
@@ -90,14 +92,18 @@ private void loadServiceEndpoints() {
90
92
91
93
for (Map .Entry <String , Node > entry : endpointMap .getStringMap ().entrySet ()) {
92
94
ObjectNode config = entry .getValue ().expectObjectNode ();
93
- if (config .containsMember ("hostname" )) {
94
- // Resolve the hostname.
95
- String hostName = config .expectStringMember ("hostname" ).getValue ();
96
- hostName = hostName .replace ("{dnsSuffix}" , dnsSuffix );
97
- hostName = hostName .replace ("{service}" , endpointPrefix );
98
- hostName = hostName .replace ("{region}" , entry .getKey ());
99
- config = config .withMember ("hostname" , hostName );
100
- endpoints .put (entry .getKey (), config );
95
+ // TODO: Do not populate config if "deprecated" is present, after fully switching to variants.
96
+ if (config .containsMember ("hostname" ) || config .containsMember ("variants" )) {
97
+ String hostname = config .getStringMemberOrDefault ("hostname" , partition .hostnameTemplate );
98
+ String resolvedHostname = getResolvedHostname (hostname , dnsSuffix , endpointPrefix , entry .getKey ());
99
+
100
+ ArrayNode variants = config .getArrayMember ("variants" ).orElse (ArrayNode .fromNodes ());
101
+ ArrayNode defaultVariant = ArrayNode .fromNodes (getDefaultVariant (resolvedHostname ));
102
+
103
+ endpoints .put (entry .getKey (),
104
+ config
105
+ .withMember ("hostname" , resolvedHostname )
106
+ .withMember ("variants" , defaultVariant .merge (variants )));
101
107
}
102
108
}
103
109
}
@@ -131,9 +137,13 @@ private void writePartitionHash() {
131
137
}
132
138
});
133
139
writer .write ("regionRegex: $S," , partition .regionRegex );
134
- OptionalUtils .ifPresentOrElse (partition .getPartitionEndpoint (),
135
- endpoint -> writer .write ("endpoint: $S," , endpoint ),
136
- () -> writer .write ("hostname: $S," , partition .hostnameTemplate ));
140
+
141
+ // TODO: Remove hostname after fully switching to variants.
142
+ writer .write ("hostname: $S," , partition .hostnameTemplate );
143
+ writer .write ("variants: $L," , ArrayNode .prettyPrintJson (partition .getVariants ()));
144
+
145
+ partition .getPartitionEndpoint ().ifPresent (
146
+ endpoint -> writer .write ("endpoint: $S," , endpoint ));
137
147
});
138
148
});
139
149
});
@@ -159,28 +169,48 @@ private void writeEndpointProviderFunction() {
159
169
}
160
170
161
171
private void writeEndpointSpecificResolver (String region , ObjectNode resolved ) {
162
- if (resolved .containsMember ("hostname" ) || resolved .containsMember ("credentialScope" )) {
163
- writer .openBlock ("$S: {" , "}," , region , () -> {
164
- String hostname = resolved .expectStringMember ("hostname" ).getValue ();
165
- writer .write ("hostname: $S," , hostname );
166
- resolved .getObjectMember ("credentialScope" ).ifPresent (scope -> {
167
- scope .getStringMember ("region" ).ifPresent (signingRegion -> {
168
- writer .write ("signingRegion: $S," , signingRegion );
169
- });
170
- scope .getStringMember ("service" ).ifPresent (signingService -> {
171
- writer .write ("signingService: $S," , signingService );
172
- });
172
+ writer .openBlock ("$S: {" , "}," , region , () -> {
173
+ // TODO: Remove hostname after fully switching to variants.
174
+ String hostname = resolved .expectStringMember ("hostname" ).getValue ();
175
+ writer .write ("hostname: $S," , hostname );
176
+
177
+ ArrayNode variants = resolved .expectArrayMember ("variants" );
178
+ writer .write ("variants: $L," , ArrayNode .prettyPrintJson (variants ));
179
+
180
+ resolved .getObjectMember ("credentialScope" ).ifPresent (scope -> {
181
+ scope .getStringMember ("region" ).ifPresent (signingRegion -> {
182
+ writer .write ("signingRegion: $S," , signingRegion );
183
+ });
184
+ scope .getStringMember ("service" ).ifPresent (signingService -> {
185
+ writer .write ("signingService: $S," , signingService );
173
186
});
174
187
});
175
- }
188
+ });
189
+ }
190
+
191
+ private ObjectNode getDefaultVariant (String hostname ) {
192
+ return ObjectNode
193
+ .fromStringMap (Collections .singletonMap ("hostname" , hostname ))
194
+ .withMember ("tags" , ArrayNode .fromStrings (Collections .emptyList ()));
195
+ }
196
+
197
+ private String getResolvedHostname (String hostnameTemplate , String dnsSuffix , String service ) {
198
+ return getResolvedHostname (hostnameTemplate , dnsSuffix , service , "{region}" );
199
+ }
200
+
201
+ private String getResolvedHostname (String hostnameTemplate , String dnsSuffix , String service , String region ) {
202
+ return hostnameTemplate
203
+ .replace ("{service}" , service )
204
+ .replace ("{region}" , region )
205
+ .replace ("{dnsSuffix}" , dnsSuffix );
176
206
}
177
207
178
208
private final class Partition {
179
209
final ObjectNode defaults ;
180
- final String hostnameTemplate ;
181
210
final String dnsSuffix ;
182
211
final String identifier ;
183
212
final String regionRegex ;
213
+ final String hostnameTemplate ;
184
214
private final ObjectNode config ;
185
215
186
216
private Partition (ObjectNode config , String partition ) {
@@ -189,15 +219,13 @@ private Partition(ObjectNode config, String partition) {
189
219
ObjectNode partitionDefaults = config .expectObjectMember ("defaults" );
190
220
defaults = partitionDefaults .merge (getService ().getObjectMember ("defaults" ).orElse (Node .objectNode ()));
191
221
192
- // Resolve the template to use for this service in this partition.
193
- String template = defaults .expectStringMember ("hostname" ).getValue ();
194
- template = template .replace ("{service}" , endpointPrefix );
195
- template = template .replace ("{dnsSuffix}" , config .expectStringMember ("dnsSuffix" ).getValue ());
196
- hostnameTemplate = template ;
197
-
198
222
dnsSuffix = config .expectStringMember ("dnsSuffix" ).getValue ();
199
223
identifier = partition ;
200
224
regionRegex = config .expectStringMember ("regionRegex" ).getValue ();
225
+
226
+ // Resolve the template to use for this service in this partition.
227
+ String hostname = defaults .expectStringMember ("hostname" ).getValue ();
228
+ hostnameTemplate = getResolvedHostname (hostname , dnsSuffix , endpointPrefix );
201
229
}
202
230
203
231
ObjectNode getDefaults () {
@@ -222,6 +250,24 @@ Set<String> getAllRegions() {
222
250
return regions ;
223
251
}
224
252
253
+ ArrayNode getVariants () {
254
+ List <Node > allVariants = new ArrayList <Node >();
255
+
256
+ allVariants .add (getDefaultVariant (hostnameTemplate ));
257
+ if (defaults .containsMember ("variants" )) {
258
+ ArrayNode variants = defaults .expectArrayMember ("variants" );
259
+ variants .forEach (variant -> {
260
+ ObjectNode variantNode = variant .expectObjectNode ();
261
+ String hostname = variantNode .expectStringMember ("hostname" ).getValue ();
262
+ String dnsSuffix = variantNode .getStringMemberOrDefault ("dnsSuffix" , this .dnsSuffix );
263
+ String resolvedHostname = getResolvedHostname (hostname , dnsSuffix , endpointPrefix );
264
+ allVariants .add (variantNode .withMember ("hostname" , resolvedHostname ).withoutMember ("dnsSuffix" ));
265
+ });
266
+ }
267
+
268
+ return ArrayNode .fromNodes (allVariants );
269
+ }
270
+
225
271
Optional <String > getPartitionEndpoint () {
226
272
ObjectNode service = getService ();
227
273
// Note: regionalized services always use regionalized endpoints.
0 commit comments