Repository: smithy-lang/smithy
Pull request #2106 (2024-01-19 13:50:47)

Support internal trait when building synthetic enum trait
When converting the normal enum trait to an enum shape, we convert the `"internal"` tag into the `@internal` trait. This updates the opposite direction conversion used to generate the synthetic enum trait to add the `"internal"` tag if the member had the `@internal` trait if it isn't already in the list of tags.

I also added a few other test cases for the member -> enum trait definition test that didn't seem to be covered, at least from the perspective of an enum shape that wasn't itself generated by converting a string shape.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.



Patch:
diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/shapes/EnumShape.java b/smithy-model/src/main/java/software/amazon/smithy/model/shapes/EnumShape.java
index 39eeb3c02..c38d6212a 100644
--- a/smithy-model/src/main/java/software/amazon/smithy/model/shapes/EnumShape.java
+++ b/smithy-model/src/main/java/software/amazon/smithy/model/shapes/EnumShape.java
@@ -18,6 +18,7 @@ package software.amazon.smithy.model.shapes;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.LinkedHashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.function.Consumer;
@@ -31,6 +32,7 @@ import software.amazon.smithy.model.traits.EnumDefinition;
 import software.amazon.smithy.model.traits.EnumTrait;
 import software.amazon.smithy.model.traits.EnumValueTrait;
 import software.amazon.smithy.model.traits.InternalTrait;
+import software.amazon.smithy.model.traits.StringListTrait;
 import software.amazon.smithy.model.traits.TagsTrait;
 import software.amazon.smithy.model.traits.Trait;
 import software.amazon.smithy.model.traits.UnitTypeTrait;
@@ -286,8 +288,16 @@ public final class EnumShape extends StringShape {
                 .orElseThrow(() -> new IllegalStateException("Enum definitions can only be made for string enums."));
         builder.value(traitValue);
         member.getTrait(DocumentationTrait.class).ifPresent(docTrait -> builder.documentation(docTrait.getValue()));
-        member.getTrait(TagsTrait.class).ifPresent(tagsTrait -> builder.tags(tagsTrait.getValues()));
         member.getTrait(DeprecatedTrait.class).ifPresent(deprecatedTrait -> builder.deprecated(true));
+
+        List<String> tags = member.getTrait(TagsTrait.class)
+                .map(StringListTrait::getValues)
+                .orElse(Collections.emptyList());
+
+        builder.tags(tags);
+        if (member.hasTrait(InternalTrait.class) && !tags.contains("internal")) {
+            builder.addTag("internal");
+        }
         return builder.build();
     }
 


Test patch:
diff --git a/smithy-model/src/test/java/software/amazon/smithy/model/shapes/EnumShapeTest.java b/smithy-model/src/test/java/software/amazon/smithy/model/shapes/EnumShapeTest.java
index 8a9e951c9..1c6d83b4d 100644
--- a/smithy-model/src/test/java/software/amazon/smithy/model/shapes/EnumShapeTest.java
+++ b/smithy-model/src/test/java/software/amazon/smithy/model/shapes/EnumShapeTest.java
@@ -499,4 +499,62 @@ public class EnumShapeTest {
         assertFalse(EnumShape.canConvertToEnum(string, false));
         assertFalse(EnumShape.canConvertToEnum(string, true));
     }
+
+    @Test
+    public void syntheticEnumSupportsDocumentation() {
+        EnumShape shape = EnumShape.builder()
+                .id("com.example#DocumentedEnum")
+                .addMember("documented", "foo", builder -> {
+                    builder.addTrait(new DocumentationTrait("bar"));
+                })
+                .build();
+
+        SyntheticEnumTrait trait = shape.expectTrait(SyntheticEnumTrait.class);
+        assertEquals("bar", trait.getValues().get(0).getDocumentation().get());
+    }
+
+    @Test
+    public void syntheticEnumSupportsDeprecated() {
+        EnumShape shape = EnumShape.builder()
+                .id("com.example#DeprecatedEnum")
+                .addMember("deprecated", "foo", builder -> {
+                    builder.addTrait(DeprecatedTrait.builder().build());
+                })
+                .build();
+
+        SyntheticEnumTrait trait = shape.expectTrait(SyntheticEnumTrait.class);
+        assertTrue(trait.getValues().get(0).isDeprecated());
+    }
+
+    @Test
+    public void syntheticEnumSupportsTags() {
+        EnumShape shape = EnumShape.builder()
+                .id("com.example#TaggedEnum")
+                .addMember("tagged", "foo", builder -> {
+                    builder.addTrait(TagsTrait.builder().addValue("bar").build());
+                })
+                .build();
+
+        SyntheticEnumTrait trait = shape.expectTrait(SyntheticEnumTrait.class);
+        assertEquals(ListUtils.of("bar"), trait.getValues().get(0).getTags());
+    }
+
+    @Test
+    public void syntheticEnumSupportsInternal() {
+        EnumShape shape = EnumShape.builder()
+                .id("com.example#InternalEnum")
+                .addMember("withoutTag", "foo", builder -> {
+                    builder.addTrait(new InternalTrait());
+                })
+                .addMember("withTag", "bar", builder -> {
+                    builder.addTrait(new InternalTrait());
+                    builder.addTrait(TagsTrait.builder().addValue("internal").build());
+                })
+                .build();
+
+        SyntheticEnumTrait trait = shape.expectTrait(SyntheticEnumTrait.class);
+        for (EnumDefinition definition : trait.getValues()) {
+            assertEquals(ListUtils.of("internal"), definition.getTags());
+        }
+    }
 }