Skip to content

Commit 3ad9987

Browse files
authored
feat: xml serde reduction (#1108)
* feat: xml serde reduction * use regular maps in StringStore * address review comments * unused import * update openBlock to java text block * update StringStore::assignKey * set StringStore final, improve readability of writeRequestQueryParam
1 parent 913ab87 commit 3ad9987

File tree

7 files changed

+210
-44
lines changed

7 files changed

+210
-44
lines changed

.changeset/selfish-pens-scream.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
---
2+
---

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ smithy-typescript-integ-tests/yarn.lock
3737

3838
# Issue https://github.com/awslabs/smithy-typescript/issues/425
3939
smithy-typescript-codegen/bin/
40+
smithy-typescript-codegen-test/bin/
4041
smithy-typescript-ssdk-codegen-test-utils/bin/
4142
smithy-typescript-codegen-test/example-weather-customizations/bin/
4243

smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/integration/EventStreamGenerator.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -490,12 +490,19 @@ private void generateErrorEventUnmarshaller(
490490
private void readEventHeaders(GenerationContext context, StructureShape event) {
491491
TypeScriptWriter writer = context.getWriter();
492492
List<MemberShape> headerMembers = event.getAllMembers().values().stream()
493-
.filter(member -> member.hasTrait(EventHeaderTrait.class)).collect(Collectors.toList());
493+
.filter(member -> member.hasTrait(EventHeaderTrait.class)).toList();
494494
for (MemberShape headerMember : headerMembers) {
495495
String memberName = headerMember.getMemberName();
496-
writer.openBlock("if (output.headers[$S] !== undefined) {", "}", memberName, () -> {
497-
writer.write("contents.$1L = output.headers[$1S].value;", memberName);
498-
});
496+
String varName = context.getStringStore().var(memberName);
497+
498+
writer.write(
499+
"""
500+
if (output.headers[$1L] !== undefined) {
501+
contents[$1L] = output.headers[$1L].value;
502+
}
503+
""",
504+
varName
505+
);
499506
}
500507
}
501508

smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/integration/HttpBindingProtocolGenerator.java

Lines changed: 55 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,10 @@ public void generateSharedComponents(GenerationContext context) {
202202
HttpProtocolGeneratorUtils.generateMetadataDeserializer(context, getApplicationProtocol().getResponseType());
203203
HttpProtocolGeneratorUtils.generateCollectBodyString(context);
204204
HttpProtocolGeneratorUtils.generateHttpBindingUtils(context);
205+
206+
writer.write(
207+
context.getStringStore().flushVariableDeclarationCode()
208+
);
205209
}
206210

207211
@Override
@@ -673,7 +677,9 @@ private void generateOperationRequestSerializer(
673677
// Get the hostname, path, port, and scheme from client's resolved endpoint.
674678
// Then construct the request from them. The client's resolved endpoint can
675679
// be default one or supplied by users.
676-
writer.write("const {hostname, protocol = $S, port, path: basePath} = await context.endpoint();", "https");
680+
681+
writer.addImport("requestBuilder", "rb", TypeScriptDependency.SMITHY_CORE);
682+
writer.write("const b = rb(input, context);");
677683

678684
writeRequestHeaders(context, operation, bindingIndex);
679685
writeResolvedPath(context, operation, bindingIndex, trait);
@@ -692,24 +698,17 @@ private void generateOperationRequestSerializer(
692698
boolean hasHostPrefix = operation.hasTrait(EndpointTrait.class);
693699
if (hasHostPrefix) {
694700
HttpProtocolGeneratorUtils.writeHostPrefix(context, operation);
701+
writer.write("b.hn(resolvedHostname);");
695702
}
696-
writer.openBlock("return new $T({", "});", requestType, () -> {
697-
writer.write("protocol,");
698-
if (hasHostPrefix) {
699-
writer.write("hostname: resolvedHostname,");
700-
} else {
701-
writer.write("hostname,");
702-
}
703-
writer.write("port,");
704-
writer.write("method: $S,", trait.getMethod());
705-
writer.write("headers,");
706-
writer.write("path: resolvedPath,");
707-
if (hasQueryComponents) {
708-
writer.write("query,");
709-
}
710-
// Always set the body,
711-
writer.write("body,");
712-
});
703+
writer.write("b.m($S)", trait.getMethod());
704+
writer.write(".h(headers)");
705+
if (hasQueryComponents) {
706+
writer.write(".q(query)");
707+
}
708+
// Always set the body,
709+
writer.write(".b(body);");
710+
711+
writer.write("return b.build();");
713712
});
714713

715714
writer.write("");
@@ -762,8 +761,7 @@ private void writeResolvedPath(
762761
: Collections.emptyMap();
763762

764763
// Always write the bound path, but only the actual segments.
765-
writer.write("let resolvedPath = `$L` + $S;",
766-
"${basePath?.endsWith('/') ? basePath.slice(0, -1) : (basePath || '')}",
764+
writer.write("b.bp(\"$L\");",
767765
"/" + trait.getUri().getSegments().stream()
768766
.filter(segment -> {
769767
if (!useEndpointsV2) {
@@ -804,7 +802,7 @@ private void writeResolvedPath(
804802

805803
// Get the correct label to use.
806804
Segment uriLabel = uriLabels.stream().filter(s -> s.getContent().equals(memberName)).findFirst().get();
807-
writer.write("resolvedPath = __resolvedPath(resolvedPath, input, '$L', $L, '$L', $L)",
805+
writer.write("b.p('$L', $L, '$L', $L)",
808806
memberName,
809807
labelValueProvider,
810808
uriLabel.toString(),
@@ -830,7 +828,7 @@ private boolean writeRequestQueryString(
830828
writer.openBlock("const query: any = map({", "});", () -> {
831829
if (!queryLiterals.isEmpty()) {
832830
// Write any query literals present in the uri.
833-
queryLiterals.forEach((k, v) -> writer.write("$S: [, $S],", k, v));
831+
queryLiterals.forEach((k, v) -> writer.write("[$L]: [, $S],", context.getStringStore().var(k), v));
834832
}
835833
// Handle any additional query params bindings.
836834
// If query string parameter is also present in httpQuery, it would be overwritten.
@@ -879,36 +877,45 @@ private void writeRequestQueryParam(
879877
String queryValue = getInputValue(
880878
context,
881879
binding.getLocation(),
882-
"input." + memberName + memberAssertionComponent,
880+
"input[" + context.getStringStore().var(memberName) + "]" + memberAssertionComponent,
883881
binding.getMember(),
884882
target
885883
);
886884

885+
String simpleAccessExpression = "input["
886+
+ context.getStringStore().var(memberName)
887+
+ "]" + memberAssertionComponent;
888+
889+
boolean isSimpleAccessExpression = Objects.equals(
890+
simpleAccessExpression,
891+
queryValue
892+
);
893+
887894
writer.addImport("expectNonNull", "__expectNonNull", TypeScriptDependency.AWS_SMITHY_CLIENT);
888895

889-
if (Objects.equals("input." + memberName + memberAssertionComponent, queryValue)) {
896+
if (isSimpleAccessExpression) {
890897
String value = isRequired ? "__expectNonNull($L, `" + memberName + "`)" : "$L";
891898
// simple undefined check
892899
writer.write(
893-
"$S: [," + value + idempotencyComponent + "],",
894-
binding.getLocationName(),
900+
"[$L]: [," + value + idempotencyComponent + "],",
901+
context.getStringStore().var(binding.getLocationName()),
895902
queryValue
896903
);
897904
} else {
898905
if (isRequired) {
899906
// __expectNonNull is immediately invoked and not inside a function.
900907
writer.write(
901-
"$S: [__expectNonNull(input.$L, `$L`) != null, () => $L],",
902-
binding.getLocationName(),
908+
"[$L]: [__expectNonNull(input.$L, `$L`) != null, () => $L],",
909+
context.getStringStore().var(binding.getLocationName()),
903910
memberName,
904911
memberName,
905912
queryValue // no idempotency token default for required members
906913
);
907914
} else {
908915
// undefined check with lazy eval
909916
writer.write(
910-
"$S: [() => input.$L !== void 0, () => ($L)$L],",
911-
binding.getLocationName(),
917+
"[$L]: [() => input.$L !== void 0, () => ($L)$L],",
918+
context.getStringStore().var(binding.getLocationName()),
912919
memberName,
913920
queryValue,
914921
idempotencyComponent
@@ -976,7 +983,9 @@ private void writeRequestHeaders(
976983
}
977984

978985
private void writeNormalHeader(GenerationContext context, HttpBinding binding) {
979-
String memberLocation = "input." + context.getSymbolProvider().toMemberName(binding.getMember());
986+
String memberLocation = "input["
987+
+ context.getStringStore().var(context.getSymbolProvider().toMemberName(binding.getMember()))
988+
+ "]";
980989
Shape target = context.getModel().expectShape(binding.getMember().getTarget());
981990

982991
String headerKey = binding.getLocationName().toLowerCase(Locale.US);
@@ -996,8 +1005,8 @@ private void writeNormalHeader(GenerationContext context, HttpBinding binding) {
9961005
}
9971006
// evaluated value has a function or method call attached
9981007
headerBuffer.put(headerKey, String.format(
999-
"'%s': [() => isSerializableHeaderValue(%s), () => %s],",
1000-
headerKey,
1008+
"[%s]: [() => isSerializableHeaderValue(%s), () => %s],",
1009+
context.getStringStore().var(headerKey),
10011010
memberLocation + defaultValue,
10021011
headerValue + defaultValue
10031012
));
@@ -1008,8 +1017,8 @@ private void writeNormalHeader(GenerationContext context, HttpBinding binding) {
10081017
value = headerValue + " || " + s.substring(s.indexOf(": ") + 2, s.length() - 1);
10091018
}
10101019
headerBuffer.put(headerKey, String.format(
1011-
"'%s': %s,",
1012-
headerKey,
1020+
"[%s]: %s,",
1021+
context.getStringStore().var(headerKey),
10131022
value
10141023
));
10151024
}
@@ -2231,14 +2240,20 @@ private void readNormalHeaders(
22312240
String memberName = context.getSymbolProvider().toMemberName(binding.getMember());
22322241
String headerName = binding.getLocationName().toLowerCase(Locale.US);
22332242
Shape target = context.getModel().expectShape(binding.getMember().getTarget());
2234-
String headerValue = getOutputValue(context, binding.getLocation(),
2235-
outputName + ".headers['" + headerName + "']", binding.getMember(), target);
2236-
String checkedValue = outputName + ".headers['" + headerName + "']";
2243+
String headerValue = getOutputValue(
2244+
context, binding.getLocation(),
2245+
outputName + ".headers[" + context.getStringStore().var(headerName) + "]",
2246+
binding.getMember(), target
2247+
);
2248+
String checkedValue = outputName + ".headers[" + context.getStringStore().var(headerName) + "]";
22372249

22382250
if (checkedValue.equals(headerValue)) {
2239-
writer.write("$L: [, $L],", memberName, headerValue);
2251+
writer.write("[$L]: [, $L],", context.getStringStore().var(memberName), headerValue);
22402252
} else {
2241-
writer.write("$L: [() => void 0 !== $L, () => $L],", memberName, checkedValue, headerValue);
2253+
writer.write(
2254+
"[$L]: [() => void 0 !== $L, () => $L],",
2255+
context.getStringStore().var(memberName), checkedValue, headerValue
2256+
);
22422257
}
22432258
}
22442259
}

smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/integration/HttpRpcProtocolGenerator.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,10 @@ public void generateSharedComponents(GenerationContext context) {
173173
// Write common request header to be shared by all requests
174174
writeSharedRequestHeaders(context);
175175
writer.write("");
176+
177+
writer.write(
178+
context.getStringStore().flushVariableDeclarationCode()
179+
);
176180
}
177181

178182
@Override

smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/integration/ProtocolGenerator.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import software.amazon.smithy.typescript.codegen.TypeScriptDelegator;
3131
import software.amazon.smithy.typescript.codegen.TypeScriptSettings;
3232
import software.amazon.smithy.typescript.codegen.TypeScriptWriter;
33+
import software.amazon.smithy.typescript.codegen.util.StringStore;
3334
import software.amazon.smithy.utils.CaseUtils;
3435
import software.amazon.smithy.utils.SmithyUnstableApi;
3536

@@ -313,6 +314,7 @@ class GenerationContext {
313314
private TypeScriptDelegator writerDelegator;
314315
private TypeScriptWriter writer;
315316
private String protocolName;
317+
private StringStore stringStore = new StringStore();
316318

317319
public TypeScriptSettings getSettings() {
318320
return settings;
@@ -400,5 +402,9 @@ public GenerationContext withWriter(TypeScriptWriter newWriter) {
400402
copyContext.setWriter(newWriter);
401403
return copyContext;
402404
}
405+
406+
public StringStore getStringStore() {
407+
return stringStore;
408+
}
403409
}
404410
}

0 commit comments

Comments
 (0)