From 58875c9f20ac97664c0a5b61e0d69bc0bb22541a Mon Sep 17 00:00:00 2001 From: George Fu Date: Fri, 5 Apr 2024 11:13:51 -0400 Subject: [PATCH] chore(codegen): move s3 transform to Java code (#5963) * chore(codegen): move s3 transform to Java code * chore: checkstyle --- clients/client-s3/src/models/models_0.ts | 1 - clients/client-s3/src/models/models_1.ts | 2 - .../aws/typescript/codegen/AddS3Config.java | 90 +++++++++++++++++++ scripts/generate-clients/s3-hack.js | 47 ---------- 4 files changed, 90 insertions(+), 50 deletions(-) diff --git a/clients/client-s3/src/models/models_0.ts b/clients/client-s3/src/models/models_0.ts index b0f9951abf6e..2d0546825431 100644 --- a/clients/client-s3/src/models/models_0.ts +++ b/clients/client-s3/src/models/models_0.ts @@ -1,6 +1,5 @@ // smithy-typescript generated code import { ExceptionOptionType as __ExceptionOptionType, SENSITIVE_STRING } from "@smithy/smithy-client"; - import { StreamingBlobTypes } from "@smithy/types"; import { S3ServiceException as __BaseException } from "./S3ServiceException"; diff --git a/clients/client-s3/src/models/models_1.ts b/clients/client-s3/src/models/models_1.ts index b66d7727cacd..96378677b77e 100644 --- a/clients/client-s3/src/models/models_1.ts +++ b/clients/client-s3/src/models/models_1.ts @@ -1,6 +1,5 @@ // smithy-typescript generated code import { ExceptionOptionType as __ExceptionOptionType, SENSITIVE_STRING } from "@smithy/smithy-client"; - import { StreamingBlobTypes } from "@smithy/types"; import { @@ -28,7 +27,6 @@ import { StorageClass, Tag, } from "./models_0"; - import { S3ServiceException as __BaseException } from "./S3ServiceException"; /** diff --git a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddS3Config.java b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddS3Config.java index 2f765ac20203..478d972ca11f 100644 --- a/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddS3Config.java +++ b/codegen/smithy-aws-typescript-codegen/src/main/java/software/amazon/smithy/aws/typescript/codegen/AddS3Config.java @@ -36,8 +36,13 @@ import software.amazon.smithy.model.shapes.OperationShape; import software.amazon.smithy.model.shapes.ServiceShape; import software.amazon.smithy.model.shapes.Shape; +import software.amazon.smithy.model.shapes.ShapeId; +import software.amazon.smithy.model.shapes.StringShape; import software.amazon.smithy.model.shapes.StructureShape; +import software.amazon.smithy.model.shapes.TimestampShape; +import software.amazon.smithy.model.traits.DeprecatedTrait; import software.amazon.smithy.model.traits.DocumentationTrait; +import software.amazon.smithy.model.traits.HttpHeaderTrait; import software.amazon.smithy.typescript.codegen.LanguageTarget; import software.amazon.smithy.typescript.codegen.TypeScriptDependency; import software.amazon.smithy.typescript.codegen.TypeScriptSettings; @@ -106,6 +111,91 @@ public Model preprocessModel(Model model, TypeScriptSettings settings) { }); } LOGGER.info("Patching " + inputShapes.size() + " input shapes with CRT notification"); + + boolean expiresShapeIsPresent = model.getShape(ShapeId.from("com.amazonaws.s3#Expires")).isPresent(); + if (expiresShapeIsPresent) { + // ExpiresString customization part 1: + // enforce that "com.amazonaws.s3#Expires" retains type=timestamp. + // add a shape "com.amazonaws.s3#ExpiresString" of type=string. + Shape expiresShape = model.getShape(ShapeId.from("com.amazonaws.s3#Expires")).get(); + TimestampShape expiresTimestampShape = TimestampShape.builder() + .id(expiresShape.getId()) + .build(); + StringShape expiresStringShape = StringShape.builder() + .id("com.amazonaws.s3#ExpiresString") + .build(); + modelBuilder + .removeShape(expiresShape.getId()) + .addShapes(expiresTimestampShape, expiresStringShape); + + // ExpiresString customization part 2: + // for any output shape member targeting Expires, add a member ExpiresString targeting ExpiresString. + // and mark Expires deprecated in favor of ExpiresString. + // move Expires documentation trait to ExpiresString. + // set the httpHeader trait of ExpiresString to be ExpiresString. + // SDK middleware will take care of copying expires header to expiresstring header prior to deserialization. + for (OperationShape operationShape : topDownIndex.getContainedOperations(serviceShape)) { + if (operationShape.getOutput().isEmpty()) { + continue; + } + StructureShape structureShape = model.expectShape( + operationShape.getOutputShape(), StructureShape.class + ); + + Set> memberEntries = structureShape + .getAllMembers() + .entrySet(); + StructureShape.Builder structureShapeBuilder = structureShape.toBuilder(); + + boolean isTargetingExpires = structureShape + .getAllMembers() + .values() + .stream() + .anyMatch(memberShape -> memberShape.getTarget().equals(expiresShape.getId())); + + if (isTargetingExpires) { + for (Map.Entry entry : memberEntries) { + String memberName = entry.getKey(); + MemberShape memberShape = entry.getValue(); + + if (memberShape.getTarget().equals(expiresShape.getId())) { + structureShapeBuilder + .removeMember(memberName) + .addMember( + memberName, + expiresTimestampShape.getId(), + (m) -> { + m + .addTrait(new DocumentationTrait("Deprecated in favor of ExpiresString.")) + .addTrait(memberShape.getTrait(HttpHeaderTrait.class).get()) + .addTrait(DeprecatedTrait.builder().build()); + } + ) + .addMember( + "ExpiresString", + expiresStringShape.getId(), + (m) -> { + m + .addTrait(memberShape.getTrait(DocumentationTrait.class).get()) + .addTrait(new HttpHeaderTrait("ExpiresString")); + } + ); + } else { + // This is done to preserve the member order + // and insert ExpiresString adjacent to Expires. + structureShapeBuilder + .removeMember(memberName) + .addMember(memberName, memberShape.getTarget(), (m) -> { + m.addTraits(memberShape.getAllTraits().values()); + }); + } + } + modelBuilder + .addShape(structureShapeBuilder.build()); + } + } + } + return modelBuilder.addShapes(inputShapes).build(); } diff --git a/scripts/generate-clients/s3-hack.js b/scripts/generate-clients/s3-hack.js index 4038ca3e4da0..02fc1c790a2d 100644 --- a/scripts/generate-clients/s3-hack.js +++ b/scripts/generate-clients/s3-hack.js @@ -23,53 +23,6 @@ module.exports = function () { namespace: "com.amazonaws.s3", }); - const expiresShape = s3ModelObject.shapes["com.amazonaws.s3#Expires"]; - if (expiresShape) { - // enforce that Expires retains type timestamp. - expiresShape.type = "timestamp"; - - // add the ExpiresString string shape. - const newShapes = {}; - for (const [shapeId, shape] of Object.entries(s3ModelObject.shapes)) { - newShapes[shapeId] = shape; - if (shapeId === "com.amazonaws.s3#Expires") { - newShapes["com.amazonaws.s3#ExpiresString"] = { - type: "string", - }; - } - } - s3ModelObject.shapes = newShapes; - - // add ExpiresString alongside output shapes containing Expires. - for (const [shapeId, shape] of Object.entries(s3ModelObject.shapes)) { - if (shape?.traits?.["smithy.api#output"]) { - const newMembers = {}; - for (const [memberName, member] of Object.entries(shape.members)) { - newMembers[memberName] = member; - if (member.target === "com.amazonaws.s3#Expires") { - const existingDoc = member.traits["smithy.api#documentation"]; - if (!member.traits) { - member.traits = {}; - } - - newMembers.ExpiresString = { - target: "com.amazonaws.s3#ExpiresString", - traits: { - ...member.traits, - "smithy.api#httpHeader": "ExpiresString", - "smithy.api#documentation": existingDoc, - }, - }; - - member.traits["smithy.api#deprecated"] = {}; - member.traits["smithy.api#documentation"] = "Deprecated in favor of ExpiresString."; - } - } - shape.members = newMembers; - } - } - } - fs.writeFileSync(s3ModelLocation, JSON.stringify(s3ModelObject, null, 2)); return () => {