Skip to content

Commit 3d29f4e

Browse files
committed
fix: nest conflicting endpoint parameters
1 parent 990a9e4 commit 3d29f4e

File tree

2 files changed

+107
-6
lines changed

2 files changed

+107
-6
lines changed

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

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

146243
writer.writeDocs("@internal");

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)