diff --git a/private/smithy-rpcv2-cbor-schema/src/schemas/schemas.ts b/private/smithy-rpcv2-cbor-schema/src/schemas/schemas.ts index 30d5939a0e6..a35afb55e51 100644 --- a/private/smithy-rpcv2-cbor-schema/src/schemas/schemas.ts +++ b/private/smithy-rpcv2-cbor-schema/src/schemas/schemas.ts @@ -1,38 +1,20 @@ -const _B = "Boolean"; -const _BL = "BooleanList"; -const _BLl = "BlobList"; -const _Bl = "Blob"; -const _By = "Byte"; const _CE = "ComplexError"; const _CNED = "ComplexNestedErrorData"; const _COD = "ClientOptionalDefaults"; -const _D = "Double"; -const _DBM = "DenseBooleanMap"; -const _DNM = "DenseNumberMap"; -const _DSM = "DenseStringMap"; -const _DSMe = "DenseSetMap"; -const _DSMen = "DenseStructMap"; -const _DT = "DateTime"; -const _De = "Defaults"; +const _D = "Defaults"; +const _DSM = "DenseSetMap"; +const _DSMe = "DenseStructMap"; const _EIO = "EmptyInputOutput"; const _ES = "EmptyStructure"; -const _F = "Float"; -const _FE = "FooEnum"; -const _FEL = "FooEnumList"; +const _F = "Foo"; const _FO = "Float16Output"; const _FS = "FractionalSeconds"; const _FSO = "FractionalSecondsOutput"; const _Fl = "Float16"; -const _Fo = "Foo"; const _GS = "GreetingStruct"; const _GWE = "GreetingWithErrors"; const _GWEO = "GreetingWithErrorsOutput"; -const _I = "Integer"; -const _IE = "IntegerEnum"; -const _IEL = "IntegerEnumList"; const _IG = "InvalidGreeting"; -const _IL = "IntegerList"; -const _L = "Long"; const _M = "Message"; const _N = "Nested"; const _NIO = "NoInputOutput"; @@ -51,30 +33,20 @@ const _RVCL = "RpcV2CborLists"; const _RVCLIO = "RpcV2CborListInputOutput"; const _RVCSM = "RpcV2CborSparseMaps"; const _RVCSMIO = "RpcV2CborSparseMapsInputOutput"; -const _S = "String"; const _SBM = "SparseBooleanMap"; -const _SL = "StringList"; +const _SL = "StructureList"; const _SLM = "StructureListMember"; -const _SLt = "StructureList"; const _SNM = "SparseNumberMap"; const _SNO = "SparseNullsOperation"; const _SNOIO = "SparseNullsOperationInputOutput"; -const _SS = "StringSet"; +const _SS = "SimpleStructure"; const _SSL = "SparseStringList"; -const _SSM = "SparseStringMap"; -const _SSMp = "SparseSetMap"; -const _SSMpa = "SparseStructMap"; +const _SSM = "SparseSetMap"; +const _SSMp = "SparseStructMap"; +const _SSMpa = "SparseStringMap"; const _SSP = "SimpleScalarProperties"; const _SSS = "SimpleScalarStructure"; -const _SSi = "SimpleStructure"; -const _Sh = "Short"; -const _T = "Timestamp"; -const _TE = "TestEnum"; -const _TIE = "TestIntEnum"; -const _TL = "TimestampList"; -const _TLo = "TopLevel"; -const _TSL = "TestStringList"; -const _TSM = "TestStringMap"; +const _TL = "TopLevel"; const _VE = "ValidationException"; const _VEF = "ValidationExceptionField"; const _VEFL = "ValidationExceptionFieldList"; @@ -189,15 +161,15 @@ export var ComplexError = error( { [_e]: _c, }, - [_TLo, _N], + [_TL, _N], [0, () => ComplexNestedErrorData], __ComplexError ); -export var ComplexNestedErrorData = struct(n1, _CNED, 0, [_Fo], [0]); +export var ComplexNestedErrorData = struct(n1, _CNED, 0, [_F], [0]); export var Defaults = struct( n1, - _De, + _D, 0, [ _dS, @@ -299,7 +271,7 @@ export var RpcV2CborDenseMapsInputOutput = struct( _RVCDMIO, 0, [_dSM, _dNM, _dBM, _dSMe, _dSMen], - [() => DenseStructMap, 128 | 1, 128 | 2, 128 | 0, map(n1, _DSMe, 0, 0, 64 | 0)] + [() => DenseStructMap, 128 | 1, 128 | 2, 128 | 0, map(n1, _DSM, 0, 0, 64 | 0)] ); export var RpcV2CborListInputOutput = struct( n1, @@ -328,7 +300,7 @@ export var SimpleScalarStructure = struct( [_tBV, _fBV, _bV, _dV, _fV, _iV, _lV, _sV, _sVt, _bVl], [2, 2, 1, 1, 1, 1, 1, 1, 0, 21] ); -export var SimpleStructure = struct(n1, _SSi, 0, [_v], [0]); +export var SimpleStructure = struct(n1, _SS, 0, [_v], [0]); export var SparseNullsOperationInputOutput = struct( n1, _SNOIO, @@ -350,7 +322,7 @@ export var RpcV2ProtocolServiceException = error( __RpcV2ProtocolServiceException ); export var ValidationExceptionFieldList = list(n0, _VEFL, 0, () => ValidationExceptionField); -export var StructureList = list(n1, _SLt, 0, () => StructureListMember); +export var StructureList = list(n1, _SL, 0, () => StructureListMember); export var TestStringList = 64 | 0; export var BlobList = 64 | 21; @@ -382,10 +354,10 @@ export var DenseBooleanMap = 128 | 2; export var DenseNumberMap = 128 | 1; -export var DenseSetMap = map(n1, _DSMe, 0, 0, 64 | 0); +export var DenseSetMap = map(n1, _DSM, 0, 0, 64 | 0); export var DenseStringMap = 128 | 0; -export var DenseStructMap = map(n1, _DSMen, 0, 0, () => GreetingStruct); +export var DenseStructMap = map(n1, _DSMe, 0, 0, () => GreetingStruct); export var SparseBooleanMap = map( n1, _SBM, @@ -406,7 +378,7 @@ export var SparseNumberMap = map( ); export var SparseSetMap = map( n1, - _SSMp, + _SSM, { [_s]: 1, }, @@ -415,7 +387,7 @@ export var SparseSetMap = map( ); export var SparseStructMap = map( n1, - _SSMpa, + _SSMp, { [_s]: 1, }, @@ -426,7 +398,7 @@ export var TestStringMap = 128 | 0; export var SparseStringMap = map( n2, - _SSM, + _SSMpa, { [_s]: 1, }, diff --git a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/schema/SchemaGenerator.java b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/schema/SchemaGenerator.java index 300843d0a2c..ee7a6f86aab 100644 --- a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/schema/SchemaGenerator.java +++ b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/schema/SchemaGenerator.java @@ -128,7 +128,6 @@ public void run() { */ private void loadShapes(Shape shape) { String absoluteName = shape.getId().toString(); - String name = shape.getId().getName(); if (shape.isMemberShape()) { loadShapes(model.expectShape(shape.asMemberShape().get().getTarget())); @@ -139,9 +138,6 @@ private void loadShapes(Shape shape) { return; } - if (!elision.isReferenceSchema(shape)) { - stringStore.var(name); - } loadShapesVisited.add(absoluteName); switch (shape.getType()) { diff --git a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/schema/SchemaReferenceIndex.java b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/schema/SchemaReferenceIndex.java index 4262b978a02..92ac13076aa 100644 --- a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/schema/SchemaReferenceIndex.java +++ b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/schema/SchemaReferenceIndex.java @@ -46,10 +46,12 @@ public boolean isReferenceSchema(Shape shape) { } ShapeType type = targetShape.getType(); switch (type) { - case BOOLEAN, STRING, BYTE, DOUBLE, FLOAT, INTEGER, LONG, SHORT, ENUM, INT_ENUM -> { - return false; - } - case TIMESTAMP, BLOB -> { + case STRING, + BOOLEAN, + BYTE, DOUBLE, FLOAT, SHORT, INTEGER, LONG, + ENUM, INT_ENUM, + BIG_INTEGER, BIG_DECIMAL, + TIMESTAMP, BLOB, DOCUMENT -> { return false; } case LIST, SET, MAP -> { diff --git a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/schema/SchemaTraitFilterIndex.java b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/schema/SchemaTraitFilterIndex.java index 14140085cbf..2df0368af2e 100644 --- a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/schema/SchemaTraitFilterIndex.java +++ b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/schema/SchemaTraitFilterIndex.java @@ -9,10 +9,12 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import java.util.TreeSet; import software.amazon.smithy.model.Model; import software.amazon.smithy.model.knowledge.KnowledgeIndex; import software.amazon.smithy.model.shapes.Shape; import software.amazon.smithy.model.shapes.ShapeId; +import software.amazon.smithy.model.traits.AuthDefinitionTrait; import software.amazon.smithy.model.traits.EndpointTrait; import software.amazon.smithy.model.traits.ErrorTrait; import software.amazon.smithy.model.traits.EventHeaderTrait; @@ -35,8 +37,8 @@ import software.amazon.smithy.model.traits.SensitiveTrait; import software.amazon.smithy.model.traits.SparseTrait; import software.amazon.smithy.model.traits.StreamingTrait; +import software.amazon.smithy.model.traits.TimestampFormatTrait; import software.amazon.smithy.model.traits.Trait; -import software.amazon.smithy.model.traits.TraitDefinition; import software.amazon.smithy.model.traits.XmlAttributeTrait; import software.amazon.smithy.model.traits.XmlFlattenedTrait; import software.amazon.smithy.model.traits.XmlNameTrait; @@ -46,11 +48,19 @@ @SmithyInternalApi final class SchemaTraitFilterIndex implements KnowledgeIndex { + private static final Set EXCLUDED_TRAITS = SetUtils.of( + // excluded due to special schema handling. + TimestampFormatTrait.ID + ); + + /** + * All of these are added by scanning the ProtocolDefinition and AuthDefinition meta traits. + * The hard coded initial list is shown as an example of what this set contains. + */ private final Set includedTraits = new HashSet<>( + // (wrapped for mutability) SetUtils.of( SparseTrait.ID, - // excluded by special schema handling. - // TimestampFormatTrait.ID, SensitiveTrait.ID, IdempotencyTokenTrait.ID, JsonNameTrait.ID, @@ -81,15 +91,18 @@ final class SchemaTraitFilterIndex implements KnowledgeIndex { private final Model model; SchemaTraitFilterIndex(Model model) { - Set shapesWithTrait = model.getShapesWithTrait(ProtocolDefinitionTrait.class); - for (Shape shape : shapesWithTrait) { - // todo(schema) use protocol and authDefinition traits as the initial allowlist. - // System.out.println("shape having authDef: " + shape.getId().getName()); + Set protocolDefinitionTraits = model.getShapesWithTrait(ProtocolDefinitionTrait.class); + Set authDefinitionTraits = model.getShapesWithTrait(AuthDefinitionTrait.class); + Set definitionTraits = new TreeSet<>(); + definitionTraits.addAll(protocolDefinitionTraits); + definitionTraits.addAll(authDefinitionTraits); + + for (Shape shape : definitionTraits) { shape.getTrait(ProtocolDefinitionTrait.class).ifPresent(protocolDefinitionTrait -> { protocolDefinitionTrait.getTraits().forEach(traitShapeId -> { - Shape traitShape = model.expectShape(traitShapeId); - TraitDefinition traitDefinition = model.getTraitDefinition(traitShapeId).get(); - // System.out.println("\t trait shape: " + traitShapeId.getName()); + if (!EXCLUDED_TRAITS.contains(traitShapeId)) { + includedTraits.add(traitShapeId); + } }); }); } @@ -104,6 +117,14 @@ public static SchemaTraitFilterIndex of(Model model) { return model.getKnowledge(SchemaTraitFilterIndex.class, SchemaTraitFilterIndex::new); } + /** + * @param traitShapeId - query. + * @return whether trait should be included in schema generation. + */ + public boolean includeTrait(ShapeId traitShapeId) { + return includedTraits.contains(traitShapeId) || SchemaTraitExtension.INSTANCE.contains(traitShapeId); + } + /** * @param shape - structure or member, usually. * @return whether it has at least 1 trait that is needed in a schema. @@ -112,7 +133,7 @@ public boolean hasSchemaTraits(Shape shape) { return hasSchemaTraits(shape, 0); } - public boolean hasSchemaTraits(Shape shape, int depth) { + private boolean hasSchemaTraits(Shape shape, int depth) { if (cache.containsKey(shape)) { return cache.get(shape); } @@ -139,12 +160,4 @@ public boolean hasSchemaTraits(Shape shape, int depth) { cache.put(shape, membersHaveSchemaTraits || targetHasSchemaTraits); return cache.get(shape); } - - /** - * @param traitShapeId - query. - * @return whether trait should be included in schema generation. - */ - public boolean includeTrait(ShapeId traitShapeId) { - return includedTraits.contains(traitShapeId) || SchemaTraitExtension.INSTANCE.contains(traitShapeId); - } } diff --git a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/schema/SchemaTraitGenerator.java b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/schema/SchemaTraitGenerator.java index ecad74ac3b5..5ea7072d4d8 100644 --- a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/schema/SchemaTraitGenerator.java +++ b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/schema/SchemaTraitGenerator.java @@ -98,16 +98,6 @@ public String serializeTraitData(Trait trait, StringStore stringStore) { return stringStore.var(strTrait.getValue()); } else if (ANNOTATION_TRAITS.contains(trait.toShapeId()) && trait instanceof AnnotationTrait) { return ANNOTATION_TRAIT_VALUE; - } else if (trait instanceof HttpErrorTrait httpError) { - return Objects.toString(httpError.getCode()); - } else if (trait instanceof HttpTrait httpTrait) { - return """ - ["%s", "%s", %s] - """.formatted( - httpTrait.getMethod(), - httpTrait.getUri(), - httpTrait.getCode() - ); } else if (DATA_TRAITS.contains(trait.toShapeId())) { if (trait instanceof EndpointTrait endpointTrait) { return """ @@ -120,6 +110,16 @@ public String serializeTraitData(Trait trait, StringStore stringStore) { stringStore.var(xmlNamespaceTrait.getPrefix().orElse("")), stringStore.var(xmlNamespaceTrait.getUri()) ); + } else if (trait instanceof HttpErrorTrait httpError) { + return Objects.toString(httpError.getCode()); + } else if (trait instanceof HttpTrait httpTrait) { + return """ + ["%s", "%s", %s] + """.formatted( + httpTrait.getMethod(), + httpTrait.getUri(), + httpTrait.getCode() + ); } } else if (SchemaTraitExtension.INSTANCE.contains(trait)) { return SchemaTraitExtension.INSTANCE.render(trait); diff --git a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/util/StringStore.java b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/util/StringStore.java index 55432c8a628..37e97e090e5 100644 --- a/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/util/StringStore.java +++ b/smithy-typescript-codegen/src/main/java/software/amazon/smithy/typescript/codegen/util/StringStore.java @@ -38,7 +38,7 @@ public final class StringStore { private final TreeMap variableToLiteral = new TreeMap<>(); // controls incremental output. - private final Set writelog = new HashSet<>(); + private final Set writeLog = new HashSet<>(); public StringStore() {} @@ -79,7 +79,7 @@ public String flushVariableDeclarationCode() { for (Map.Entry entry : variableToLiteral.entrySet()) { String variable = entry.getKey(); String literal = entry.getValue(); - if (writelog.add(variable)) { + if (writeLog.add(variable)) { sourceCode.append(String.format("const %s = \"%s\";%n", variable, literal)); } } diff --git a/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/schema/SchemaReferenceIndexTest.java b/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/schema/SchemaReferenceIndexTest.java new file mode 100644 index 00000000000..2151d0be4b9 --- /dev/null +++ b/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/schema/SchemaReferenceIndexTest.java @@ -0,0 +1,78 @@ +package software.amazon.smithy.typescript.codegen.schema; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import java.util.Set; +import java.util.function.Function; +import java.util.stream.Stream; +import software.amazon.smithy.model.Model; +import software.amazon.smithy.model.shapes.CollectionShape; +import software.amazon.smithy.model.shapes.MapShape; +import software.amazon.smithy.model.shapes.Shape; +import software.amazon.smithy.model.shapes.SimpleShape; +import software.amazon.smithy.model.shapes.StructureShape; +import software.amazon.smithy.typescript.codegen.knowledge.SerdeElisionIndexTest; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertFalse; + +class SchemaReferenceIndexTest { + private static Model model; + private static SchemaReferenceIndex subject; + + @BeforeAll + public static void before() { + model = Model.assembler() + .addImport(SerdeElisionIndexTest.class.getResource("serde-elision.smithy")) + .assemble() + .unwrap(); + subject = new SchemaReferenceIndex(model); + } + + @Test + void isReferenceSchema() { + Stream simpleShapes = Stream.of( + model.getStringShapes().stream(), + model.getBooleanShapes().stream(), + model.getByteShapes().stream(), + model.getDoubleShapes().stream(), + model.getFloatShapes().stream(), + model.getShortShapes().stream(), + model.getIntegerShapes().stream(), + model.getLongShapes().stream(), + model.getEnumShapes().stream(), + model.getIntEnumShapes().stream(), + model.getBigIntegerShapes().stream(), + model.getBigDecimalShapes().stream(), + model.getTimestampShapes().stream(), + model.getBlobShapes().stream(), + model.getDocumentShapes().stream() + ).flatMap(Function.identity()); + simpleShapes.forEach(booleanShape -> { + assertFalse(subject.isReferenceSchema(booleanShape)); + }); + + Set structureShapes = model.getStructureShapes(); + structureShapes.forEach(structureShape -> { + assertTrue(subject.isReferenceSchema(structureShape)); + }); + + Stream collectionShapes = Stream.of( + model.getSetShapes().stream(), + model.getListShapes().stream(), + model.getMapShapes().stream() + ).flatMap(Function.identity()); + collectionShapes.forEach(shape -> { + boolean isRef; + if (shape instanceof CollectionShape collection) { + isRef = subject.isReferenceSchema(collection.getMember()); + } else if (shape instanceof MapShape map) { + isRef = subject.isReferenceSchema(map.getValue()); + } else { + throw new UnsupportedOperationException("Unexpected shape type"); + } + assertEquals(isRef, subject.isReferenceSchema(shape)); + }); + } +} \ No newline at end of file diff --git a/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/schema/SchemaTraitExtensionTest.java b/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/schema/SchemaTraitExtensionTest.java new file mode 100644 index 00000000000..7f85e0d1a5f --- /dev/null +++ b/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/schema/SchemaTraitExtensionTest.java @@ -0,0 +1,38 @@ +package software.amazon.smithy.typescript.codegen.schema; + +import org.junit.jupiter.api.Test; +import software.amazon.smithy.model.traits.JsonNameTrait; + +import static org.junit.jupiter.api.Assertions.*; + +class SchemaTraitExtensionTest { + private static final SchemaTraitExtension subject = SchemaTraitExtension.INSTANCE; + + @Test + void add() { + subject.add(JsonNameTrait.ID, Object::toString); + } + + @Test + void contains() { + subject.add(JsonNameTrait.ID, Object::toString); + assertTrue(subject.contains(JsonNameTrait.ID)); + JsonNameTrait trait = new JsonNameTrait("test"); + assertTrue(subject.contains(trait)); + } + + @Test + void render() { + JsonNameTrait trait = new JsonNameTrait("test"); + subject.add(JsonNameTrait.ID, _trait -> { + if (_trait instanceof JsonNameTrait jsonNameTrait) { + return jsonNameTrait.getValue() + "__test"; + } + throw new UnsupportedOperationException("wrong trait type"); + }); + assertEquals( + "test__test", + subject.render(trait) + ); + } +} \ No newline at end of file diff --git a/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/schema/SchemaTraitFilterIndexTest.java b/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/schema/SchemaTraitFilterIndexTest.java new file mode 100644 index 00000000000..b36eab1f51b --- /dev/null +++ b/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/schema/SchemaTraitFilterIndexTest.java @@ -0,0 +1,113 @@ +package software.amazon.smithy.typescript.codegen.schema; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.model.Model; +import software.amazon.smithy.model.shapes.Shape; +import software.amazon.smithy.model.shapes.ShapeId; +import software.amazon.smithy.model.traits.EndpointTrait; +import software.amazon.smithy.model.traits.ErrorTrait; +import software.amazon.smithy.model.traits.EventHeaderTrait; +import software.amazon.smithy.model.traits.EventPayloadTrait; +import software.amazon.smithy.model.traits.HostLabelTrait; +import software.amazon.smithy.model.traits.HttpErrorTrait; +import software.amazon.smithy.model.traits.HttpHeaderTrait; +import software.amazon.smithy.model.traits.HttpLabelTrait; +import software.amazon.smithy.model.traits.HttpPayloadTrait; +import software.amazon.smithy.model.traits.HttpPrefixHeadersTrait; +import software.amazon.smithy.model.traits.HttpQueryParamsTrait; +import software.amazon.smithy.model.traits.HttpQueryTrait; +import software.amazon.smithy.model.traits.HttpResponseCodeTrait; +import software.amazon.smithy.model.traits.HttpTrait; +import software.amazon.smithy.model.traits.IdempotencyTokenTrait; +import software.amazon.smithy.model.traits.JsonNameTrait; +import software.amazon.smithy.model.traits.MediaTypeTrait; +import software.amazon.smithy.model.traits.RequiresLengthTrait; +import software.amazon.smithy.model.traits.SensitiveTrait; +import software.amazon.smithy.model.traits.SparseTrait; +import software.amazon.smithy.model.traits.StreamingTrait; +import software.amazon.smithy.model.traits.TimestampFormatTrait; +import software.amazon.smithy.model.traits.XmlAttributeTrait; +import software.amazon.smithy.model.traits.XmlFlattenedTrait; +import software.amazon.smithy.model.traits.XmlNameTrait; +import software.amazon.smithy.model.traits.XmlNamespaceTrait; +import software.amazon.smithy.typescript.codegen.knowledge.SerdeElisionIndexTest; +import software.amazon.smithy.utils.SetUtils; + +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.*; + +class SchemaTraitFilterIndexTest { + private static Model model; + private static SchemaTraitFilterIndex subject; + + @BeforeAll + public static void before() { + model = Model.assembler() + .addImport(SerdeElisionIndexTest.class.getResource("serde-elision.smithy")) + .assemble() + .unwrap(); + subject = new SchemaTraitFilterIndex(model); + } + + + @Test + void hasSchemaTraits() { + Set sparseShapes = model.getShapesWithTrait(SparseTrait.class); + assertFalse(sparseShapes.isEmpty()); + + for (Shape sparseShape : sparseShapes) { + assertTrue(subject.hasSchemaTraits(sparseShape)); + assertTrue( + subject.includeTrait( + sparseShape.getTrait(SparseTrait.class).get().toShapeId() + ) + ); + } + } + + @Test + void includeTrait() { + Set excludedShapes = SetUtils.of( + TimestampFormatTrait.ID + ); + for (ShapeId excludedShape : excludedShapes) { + String presence = subject.includeTrait(excludedShape) + ? "should not be included" + : excludedShape.getName(); + assertEquals(excludedShape.getName(), presence); + } + Set includedTraits = SetUtils.of( + SparseTrait.ID, + SensitiveTrait.ID, + IdempotencyTokenTrait.ID, + JsonNameTrait.ID, + MediaTypeTrait.ID, + XmlAttributeTrait.ID, + XmlFlattenedTrait.ID, + XmlNameTrait.ID, + XmlNamespaceTrait.ID, + EventHeaderTrait.ID, + EventPayloadTrait.ID, + StreamingTrait.ID, + RequiresLengthTrait.ID, + EndpointTrait.ID, + HttpErrorTrait.ID, + HttpHeaderTrait.ID, + HttpQueryTrait.ID, + HttpLabelTrait.ID, + HttpPayloadTrait.ID, + HttpPrefixHeadersTrait.ID, + HttpQueryParamsTrait.ID, + HttpResponseCodeTrait.ID, + HostLabelTrait.ID, + ErrorTrait.ID, + HttpTrait.ID + ); + for (ShapeId includedTrait : includedTraits) { + String presence = subject.includeTrait(includedTrait) ? includedTrait.getName() : "is missing"; + assertEquals(includedTrait.getName(), presence); + } + } +} \ No newline at end of file diff --git a/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/schema/SchemaTraitGeneratorTest.java b/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/schema/SchemaTraitGeneratorTest.java new file mode 100644 index 00000000000..ce07beb638d --- /dev/null +++ b/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/schema/SchemaTraitGeneratorTest.java @@ -0,0 +1,59 @@ +package software.amazon.smithy.typescript.codegen.schema; + +import org.junit.jupiter.api.Test; +import software.amazon.smithy.model.pattern.UriPattern; +import software.amazon.smithy.model.traits.EndpointTrait; +import software.amazon.smithy.model.traits.HttpErrorTrait; +import software.amazon.smithy.model.traits.HttpTrait; +import software.amazon.smithy.model.traits.JsonNameTrait; +import software.amazon.smithy.model.traits.TimestampFormatTrait; +import software.amazon.smithy.model.traits.Trait; +import software.amazon.smithy.model.traits.XmlAttributeTrait; +import software.amazon.smithy.model.traits.XmlNamespaceTrait; +import software.amazon.smithy.typescript.codegen.util.StringStore; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +class SchemaTraitGeneratorTest { + private static final SchemaTraitGenerator subject = new SchemaTraitGenerator(); + + private record TestPair(String expectedSerialization, Trait trait) { + public void test() { + assertEquals(expectedSerialization, subject.serializeTraitData(trait, new StringStore())); + } + } + + private static final List testCases = List.of( + // timestamp + new TestPair("", new TimestampFormatTrait("date-time")), + // strings + new TestPair("_jN", new JsonNameTrait("jsonName")), + + // annotations + new TestPair("1", new XmlAttributeTrait()), + + // data traits + new TestPair("[\"prefix\"]\n", EndpointTrait.builder() + .hostPrefix("prefix") + .build()), + new TestPair("[_p, _h]\n", XmlNamespaceTrait.builder() + .prefix("prefix") + .uri("https://localhost") + .build()), + new TestPair("404", new HttpErrorTrait(404)), + new TestPair("[\"GET\", \"/uri-pattern\", 200]\n", HttpTrait.builder() + .method("GET") + .uri(UriPattern.parse("/uri-pattern")) + .code(200) + .build()) + ); + + @Test + void serializeTraitData() { + for (TestPair testCase : testCases) { + testCase.test(); + } + } +} \ No newline at end of file diff --git a/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/schema/SchemaTraitWriterTest.java b/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/schema/SchemaTraitWriterTest.java new file mode 100644 index 00000000000..a279d9f6071 --- /dev/null +++ b/smithy-typescript-codegen/src/test/java/software/amazon/smithy/typescript/codegen/schema/SchemaTraitWriterTest.java @@ -0,0 +1,49 @@ +package software.amazon.smithy.typescript.codegen.schema; + +import java.util.Set; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import software.amazon.smithy.model.Model; +import software.amazon.smithy.model.shapes.Shape; +import software.amazon.smithy.model.traits.StreamingTrait; +import software.amazon.smithy.typescript.codegen.knowledge.SerdeElisionIndexTest; +import software.amazon.smithy.typescript.codegen.util.StringStore; + +import static org.junit.jupiter.api.Assertions.*; + +class SchemaTraitWriterTest { + private static Model model; + private static SchemaReferenceIndex schemaReferenceIndex; + private static SchemaTraitWriter subject; + + @BeforeAll + public static void before() { + model = Model.assembler() + .addImport(SerdeElisionIndexTest.class.getResource("serde-elision.smithy")) + .assemble() + .unwrap(); + schemaReferenceIndex = new SchemaReferenceIndex(model); + subject = new SchemaTraitWriter( + null, + schemaReferenceIndex, + new StringStore() + ); + } + + @Test + void testToString() { + Set streamingShapes = model.getShapesWithTrait(StreamingTrait.class); + assertEquals(1, streamingShapes.size()); + for (Shape streamingShape : streamingShapes) { + subject = new SchemaTraitWriter( + streamingShape, + schemaReferenceIndex, + new StringStore() + ); + String codeGeneration = subject.toString(); + assertEquals(""" + { + [_s]: 1,}""", codeGeneration); + } + } +} \ No newline at end of file