Skip to content

Commit c0cc0c7

Browse files
committed
fix: nest conflicting endpoint parameters
1 parent f8bed21 commit c0cc0c7

File tree

2 files changed

+107
-7
lines changed

2 files changed

+107
-7
lines changed

smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/endpointsV2/EndpointsV2Generator.java

Lines changed: 103 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@
1717

1818
import java.nio.file.Paths;
1919
import java.util.Collections;
20+
import java.util.HashMap;
2021
import java.util.HashSet;
2122
import java.util.List;
2223
import java.util.Map;
2324
import java.util.Set;
2425
import java.util.stream.Collectors;
2526
import software.amazon.smithy.codegen.core.SymbolDependency;
2627
import software.amazon.smithy.model.Model;
28+
import software.amazon.smithy.model.node.Node;
2729
import software.amazon.smithy.model.node.ObjectNode;
2830
import software.amazon.smithy.model.shapes.ServiceShape;
2931
import software.amazon.smithy.rulesengine.traits.EndpointRuleSetTrait;
@@ -117,31 +119,125 @@ private void generateEndpointParameters() {
117119
"export interface ClientInputEndpointParameters {",
118120
"}",
119121
() -> {
120-
Map<String, String> clientInputParams = ruleSetParameterFinder.getClientContextParams();
121-
//Omit Endpoint params that should not be a part of the ClientInputEndpointParameters interface
122+
Map<String, String> clientContextParams =
123+
ruleSetParameterFinder.getClientContextParams();
122124
Map<String, String> builtInParams = ruleSetParameterFinder.getBuiltInParams();
123125
builtInParams.keySet().removeIf(OmitEndpointParams::isOmitted);
124-
clientInputParams.putAll(builtInParams);
125-
126+
Set<String> knownConfigKeys = Set.of(
127+
"apiKey", "retryStrategy", "requestHandler");
128+
// Generate clientContextParams with all params excluding built-ins
129+
Map<String, String> customerContextParams = new HashMap<>();
130+
for (Map.Entry<String, String> entry : clientContextParams.entrySet()) {
131+
if (!builtInParams.containsKey(entry.getKey())) {
132+
customerContextParams.put(entry.getKey(), entry.getValue());
133+
}
134+
}
135+
if (!customerContextParams.isEmpty()) {
136+
writer.write("clientContextParams: {");
137+
writer.indent();
138+
ObjectNode ruleSet = endpointRuleSetTrait.getRuleSet().expectObjectNode();
139+
ruleSet.getObjectMember("parameters").ifPresent(parameters -> {
140+
parameters.accept(new RuleSetParametersVisitor(
141+
writer, customerContextParams, true));
142+
});
143+
writer.dedent();
144+
writer.write("};");
145+
}
146+
// Add direct params (built-ins + non-conflicting client context params)
147+
Map<String, String> directParams = new HashMap<>(builtInParams);
148+
for (Map.Entry<String, String> entry : clientContextParams.entrySet()) {
149+
// Only add non-conflicting client context params that aren't built-ins
150+
if (!knownConfigKeys.contains(entry.getKey())
151+
&& !builtInParams.containsKey(entry.getKey())) {
152+
directParams.put(entry.getKey(), entry.getValue());
153+
}
154+
}
126155
ObjectNode ruleSet = endpointRuleSetTrait.getRuleSet().expectObjectNode();
127156
ruleSet.getObjectMember("parameters").ifPresent(parameters -> {
128-
parameters.accept(new RuleSetParametersVisitor(writer, clientInputParams, true));
157+
parameters.accept(new RuleSetParametersVisitor(writer, directParams, true));
129158
});
130159
}
131160
);
132161

133162
writer.write("");
134-
writer.openBlock(
163+
writer.openBlock(
135164
"""
136165
export type ClientResolvedEndpointParameters = Omit<ClientInputEndpointParameters, "endpoint"> & {
137166
""",
138167
"};",
139168
() -> {
140169
writer.write("defaultSigningName: string;");
170+
// Add clientContextParams with same structure as input
171+
Map<String, String> clientContextParams = ruleSetParameterFinder.getClientContextParams();
172+
Map<String, String> customerContextParams = new HashMap<>();
173+
Map<String, String> builtInParams = ruleSetParameterFinder.getBuiltInParams();
174+
for (Map.Entry<String, String> entry : clientContextParams.entrySet()) {
175+
if (!builtInParams.containsKey(entry.getKey())) {
176+
customerContextParams.put(entry.getKey(), entry.getValue());
177+
}
178+
}
179+
if (!customerContextParams.isEmpty()) {
180+
writer.write("clientContextParams: {");
181+
writer.indent();
182+
ObjectNode ruleSet = endpointRuleSetTrait.getRuleSet().expectObjectNode();
183+
ruleSet.getObjectMember("parameters").ifPresent(parameters -> {
184+
parameters.accept(new RuleSetParametersVisitor(
185+
writer, customerContextParams, false));
186+
});
187+
writer.dedent();
188+
writer.write("};");
189+
}
141190
}
142191
);
192+
// Generate clientContextParamDefaults only if there are customer context params
193+
Map<String, String> clientContextParams = ruleSetParameterFinder.getClientContextParams();
194+
Map<String, String> builtInParams = ruleSetParameterFinder.getBuiltInParams();
195+
Map<String, String> customerContextParams = new HashMap<>();
196+
for (Map.Entry<String, String> entry : clientContextParams.entrySet()) {
197+
if (!builtInParams.containsKey(entry.getKey())) {
198+
customerContextParams.put(entry.getKey(), entry.getValue());
199+
}
200+
}
201+
if (!customerContextParams.isEmpty()) {
202+
// Check if any parameters have default values
203+
boolean hasDefaults = false;
204+
ObjectNode ruleSet = endpointRuleSetTrait.getRuleSet().expectObjectNode();
205+
if (ruleSet.getObjectMember("parameters").isPresent()) {
206+
ObjectNode parameters = ruleSet.getObjectMember("parameters").get().expectObjectNode();
207+
for (Map.Entry<String, String> entry : customerContextParams.entrySet()) {
208+
String paramName = entry.getKey();
209+
ObjectNode paramNode = parameters.getObjectMember(paramName).orElse(null);
210+
if (paramNode != null && paramNode.containsMember("default")) {
211+
hasDefaults = true;
212+
break;
213+
}
214+
}
215+
}
216+
if (hasDefaults) {
217+
writer.write("");
218+
writer.writeDocs("@internal");
219+
writer.openBlock("const clientContextParamDefaults = {", "} as const;", () -> {
220+
ruleSet.getObjectMember("parameters").ifPresent(parameters -> {
221+
for (Map.Entry<String, String> entry : customerContextParams.entrySet()) {
222+
String paramName = entry.getKey();
223+
ObjectNode paramNode = parameters.expectObjectNode()
224+
.getObjectMember(paramName).orElse(null);
225+
if (paramNode != null && paramNode.containsMember("default")) {
226+
Node defaultValue = paramNode.getMember("default").get();
227+
if (defaultValue.isStringNode()) {
228+
writer.write("$L: \"$L\",", paramName,
229+
defaultValue.expectStringNode().getValue());
230+
} else if (defaultValue.isBooleanNode()) {
231+
writer.write("$L: $L,", paramName,
232+
defaultValue.expectBooleanNode().getValue());
233+
}
234+
}
235+
}
236+
});
237+
});
238+
}
239+
}
143240
writer.write("");
144-
145241
writer.openBlock(
146242
"export const resolveClientEndpointParameters = "
147243
+ "<T>(options: T & ClientInputEndpointParameters"

smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/endpointsV2/EndpointsV2GeneratorTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ public void containsExtraContextParameter() {
6161
assertThat(endpointParameters, containsString(
6262
"""
6363
export interface ClientInputEndpointParameters {
64+
clientContextParams: {
65+
region?: string | undefined | Provider<string | undefined>;
66+
stage?: string | undefined | Provider<string | undefined>;
67+
};
6468
region?: string | undefined | Provider<string | undefined>;
6569
stage?: string | undefined | Provider<string | undefined>;
6670
endpoint?:"""));

0 commit comments

Comments
 (0)