|
36 | 36 | import software.amazon.smithy.model.shapes.OperationShape; |
37 | 37 | import software.amazon.smithy.model.shapes.ServiceShape; |
38 | 38 | import software.amazon.smithy.model.shapes.Shape; |
| 39 | +import software.amazon.smithy.model.shapes.ShapeId; |
| 40 | +import software.amazon.smithy.model.shapes.StringShape; |
39 | 41 | import software.amazon.smithy.model.shapes.StructureShape; |
| 42 | +import software.amazon.smithy.model.shapes.TimestampShape; |
| 43 | +import software.amazon.smithy.model.traits.DeprecatedTrait; |
40 | 44 | import software.amazon.smithy.model.traits.DocumentationTrait; |
| 45 | +import software.amazon.smithy.model.traits.HttpHeaderTrait; |
41 | 46 | import software.amazon.smithy.typescript.codegen.LanguageTarget; |
42 | 47 | import software.amazon.smithy.typescript.codegen.TypeScriptDependency; |
43 | 48 | import software.amazon.smithy.typescript.codegen.TypeScriptSettings; |
@@ -106,6 +111,91 @@ public Model preprocessModel(Model model, TypeScriptSettings settings) { |
106 | 111 | }); |
107 | 112 | } |
108 | 113 | LOGGER.info("Patching " + inputShapes.size() + " input shapes with CRT notification"); |
| 114 | + |
| 115 | + boolean expiresShapeIsPresent = model.getShape(ShapeId.from("com.amazonaws.s3#Expires")).isPresent(); |
| 116 | + if (expiresShapeIsPresent) { |
| 117 | + // ExpiresString customization part 1: |
| 118 | + // enforce that "com.amazonaws.s3#Expires" retains type=timestamp. |
| 119 | + // add a shape "com.amazonaws.s3#ExpiresString" of type=string. |
| 120 | + Shape expiresShape = model.getShape(ShapeId.from("com.amazonaws.s3#Expires")).get(); |
| 121 | + TimestampShape expiresTimestampShape = TimestampShape.builder() |
| 122 | + .id(expiresShape.getId()) |
| 123 | + .build(); |
| 124 | + StringShape expiresStringShape = StringShape.builder() |
| 125 | + .id("com.amazonaws.s3#ExpiresString") |
| 126 | + .build(); |
| 127 | + modelBuilder |
| 128 | + .removeShape(expiresShape.getId()) |
| 129 | + .addShapes(expiresTimestampShape, expiresStringShape); |
| 130 | + |
| 131 | + // ExpiresString customization part 2: |
| 132 | + // for any output shape member targeting Expires, add a member ExpiresString targeting ExpiresString. |
| 133 | + // and mark Expires deprecated in favor of ExpiresString. |
| 134 | + // move Expires documentation trait to ExpiresString. |
| 135 | + // set the httpHeader trait of ExpiresString to be ExpiresString. |
| 136 | + // SDK middleware will take care of copying expires header to expiresstring header prior to deserialization. |
| 137 | + for (OperationShape operationShape : topDownIndex.getContainedOperations(serviceShape)) { |
| 138 | + if (operationShape.getOutput().isEmpty()) { |
| 139 | + continue; |
| 140 | + } |
| 141 | + StructureShape structureShape = model.expectShape( |
| 142 | + operationShape.getOutputShape(), StructureShape.class |
| 143 | + ); |
| 144 | + |
| 145 | + Set<Map.Entry<String, MemberShape>> memberEntries = structureShape |
| 146 | + .getAllMembers() |
| 147 | + .entrySet(); |
| 148 | + StructureShape.Builder structureShapeBuilder = structureShape.toBuilder(); |
| 149 | + |
| 150 | + boolean isTargetingExpires = structureShape |
| 151 | + .getAllMembers() |
| 152 | + .values() |
| 153 | + .stream() |
| 154 | + .anyMatch(memberShape -> memberShape.getTarget().equals(expiresShape.getId())); |
| 155 | + |
| 156 | + if (isTargetingExpires) { |
| 157 | + for (Map.Entry<String, MemberShape> entry : memberEntries) { |
| 158 | + String memberName = entry.getKey(); |
| 159 | + MemberShape memberShape = entry.getValue(); |
| 160 | + |
| 161 | + if (memberShape.getTarget().equals(expiresShape.getId())) { |
| 162 | + structureShapeBuilder |
| 163 | + .removeMember(memberName) |
| 164 | + .addMember( |
| 165 | + memberName, |
| 166 | + expiresTimestampShape.getId(), |
| 167 | + (m) -> { |
| 168 | + m |
| 169 | + .addTrait(new DocumentationTrait("Deprecated in favor of ExpiresString.")) |
| 170 | + .addTrait(memberShape.getTrait(HttpHeaderTrait.class).get()) |
| 171 | + .addTrait(DeprecatedTrait.builder().build()); |
| 172 | + } |
| 173 | + ) |
| 174 | + .addMember( |
| 175 | + "ExpiresString", |
| 176 | + expiresStringShape.getId(), |
| 177 | + (m) -> { |
| 178 | + m |
| 179 | + .addTrait(memberShape.getTrait(DocumentationTrait.class).get()) |
| 180 | + .addTrait(new HttpHeaderTrait("ExpiresString")); |
| 181 | + } |
| 182 | + ); |
| 183 | + } else { |
| 184 | + // This is done to preserve the member order |
| 185 | + // and insert ExpiresString adjacent to Expires. |
| 186 | + structureShapeBuilder |
| 187 | + .removeMember(memberName) |
| 188 | + .addMember(memberName, memberShape.getTarget(), (m) -> { |
| 189 | + m.addTraits(memberShape.getAllTraits().values()); |
| 190 | + }); |
| 191 | + } |
| 192 | + } |
| 193 | + modelBuilder |
| 194 | + .addShape(structureShapeBuilder.build()); |
| 195 | + } |
| 196 | + } |
| 197 | + } |
| 198 | + |
109 | 199 | return modelBuilder.addShapes(inputShapes).build(); |
110 | 200 | } |
111 | 201 |
|
|
0 commit comments