diff --git a/.changes/next-release/feature-d17968aca46bca4363e20d02a48b457df03623ec.json b/.changes/next-release/feature-d17968aca46bca4363e20d02a48b457df03623ec.json new file mode 100644 index 00000000000..2faea4a956f --- /dev/null +++ b/.changes/next-release/feature-d17968aca46bca4363e20d02a48b457df03623ec.json @@ -0,0 +1,7 @@ +{ + "type": "feature", + "description": "Updated tags member names validation in input/output structures to allow \"map\" suffix variants.", + "pull_requests": [ + "[#3129](https://github.com/smithy-lang/smithy/pull/3129)" + ] +} diff --git a/docs/source-2.0/aws/aws-core.rst b/docs/source-2.0/aws/aws-core.rst index da49119eb04..3a066953803 100644 --- a/docs/source-2.0/aws/aws-core.rst +++ b/docs/source-2.0/aws/aws-core.rst @@ -1348,10 +1348,11 @@ tag associations on a resource: * Must have exactly one input member that targets a string shape and has a member name that matches ``^([R|r]esource)?([A|a]rn|ARN)$`` to accept the resource ARN. -* Must have exactly one input member that targets a list shape, with list - member targeting a structure that consists of two members that target a - string shape representing the tag key or name and the tag value. This - member name must match: ``^[T|t]ag(s|[L|l]ist)$`` +* Must have exactly one input member that targets either a list shape (with + list member targeting a structure of two string members representing the + tag key and tag value) or a map shape with string keys and values. This + member name must match: ``^[T|t]ag(s|s?[M|m]ap|[L|l]ist)$`` (e.g., ``tags``, + ``TagList``, ``tagMap``, ``tagsMap``). The following snippet is a valid definition of a tag resource operation and its input: @@ -1416,10 +1417,11 @@ resource. * Must have exactly one input member that targets a string shape and has a member name that matches: ``^([R|r]esource)?([A|a]rn|ARN)$`` to accept the resource ARN. -* Must have exactly one output member that targets a list shape, with list - member targeting a structure that consists of two members that target a - string shape representing the tag key or name and the tag value. This - member name must match: ``^[T|t]ag(s|[L|l]ist)$`` +* Must have exactly one output member that targets either a list shape (with + list member targeting a structure of two string members representing the + tag key and tag value) or a map shape with string keys and values. This + member name must match: ``^[T|t]ag(s|s?[M|m]ap|[L|l]ist)$`` (e.g., ``tags``, + ``TagList``, ``tagMap``, ``tagsMap``). The following snippet is an example of the list tags for resource operation and its input: diff --git a/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/tagging/TaggingShapeUtils.java b/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/tagging/TaggingShapeUtils.java index 1740132be3b..722b28cca8b 100644 --- a/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/tagging/TaggingShapeUtils.java +++ b/smithy-aws-traits/src/main/java/software/amazon/smithy/aws/traits/tagging/TaggingShapeUtils.java @@ -29,7 +29,7 @@ final class TaggingShapeUtils { static final String LIST_TAGS_OPNAME = "ListTagsForResource"; private static final Pattern TAG_PROPERTY_REGEX = Pattern - .compile("^[T|t]ag(s|[L|l]ist)$"); + .compile("^[T|t]ag(s|s?[M|m]ap|[L|l]ist)$"); private static final Pattern RESOURCE_ARN_REGEX = Pattern .compile("^([R|r]esource)?([A|a]rn|ARN)?$"); private static final Pattern TAG_KEYS_REGEX = Pattern diff --git a/smithy-aws-traits/src/test/java/software/amazon/smithy/aws/traits/tagging/TaggingShapeUtilsTest.java b/smithy-aws-traits/src/test/java/software/amazon/smithy/aws/traits/tagging/TaggingShapeUtilsTest.java index d73ddd1ab65..5a0c9bb5ee3 100644 --- a/smithy-aws-traits/src/test/java/software/amazon/smithy/aws/traits/tagging/TaggingShapeUtilsTest.java +++ b/smithy-aws-traits/src/test/java/software/amazon/smithy/aws/traits/tagging/TaggingShapeUtilsTest.java @@ -36,4 +36,39 @@ public static List arnMembers() { public void isArnMemberDesiredName(String arnMember, boolean expected) { assertEquals(expected, TaggingShapeUtils.isArnMemberDesiredName(arnMember)); } + + public static List tagMembers() { + return ListUtils.of( + // accepted plural / list forms (existing) + Arguments.of("Tags", true), + Arguments.of("tags", true), + Arguments.of("TagList", true), + Arguments.of("tagList", true), + Arguments.of("Taglist", true), + Arguments.of("taglist", true), + // accepted map forms (new) + Arguments.of("TagMap", true), + Arguments.of("tagMap", true), + Arguments.of("Tagmap", true), + Arguments.of("tagmap", true), + Arguments.of("TagsMap", true), + Arguments.of("tagsMap", true), + Arguments.of("Tagsmap", true), + Arguments.of("tagsmap", true), + // rejected + Arguments.of("", false), + Arguments.of("Tag", false), + Arguments.of("tag", false), + Arguments.of("Tagger", false), + Arguments.of("tagging", false), + Arguments.of("mytags", false), + Arguments.of("Maptag", false), + Arguments.of("Maps", false)); + } + + @ParameterizedTest + @MethodSource("tagMembers") + public void isTagDesiredName(String memberName, boolean expected) { + assertEquals(expected, TaggingShapeUtils.isTagDesiredName(memberName)); + } }