diff --git a/docs/source/1.0/spec/core/idl.rst b/docs/source/1.0/spec/core/idl.rst index f9679a53469..6b53ac81d25 100644 --- a/docs/source/1.0/spec/core/idl.rst +++ b/docs/source/1.0/spec/core/idl.rst @@ -207,7 +207,9 @@ The Smithy IDL is defined by the following ABNF: trait_body_value :`trait_structure` / `node_value` trait_structure :`trait_structure_kvp` *(`ws` `trait_structure_kvp`) trait_structure_kvp :`node_object_key` `ws` ":" `ws` `node_value` - apply_statement :"apply" `ws` `shape_id` `ws` `trait` `ws` + apply_statement :`apply_statement_singular` / `apply_statement_block` + apply_statement_singular: "apply" `ws` `shape_id` `ws` `trait` `ws` + apply_statement_block: "apply" `ws` `shape_id` `ws` "{" `trait_statements` "}" .. rubric:: Shape ID @@ -1491,22 +1493,52 @@ Apply statement Traits can be applied to shapes outside of a shape's definition using an :token:`apply_statement`. -The following example applies the :ref:`documentation-trait` and -:ref:`length-trait` to the ``smithy.example#MyString`` shape: +The following example applies the :ref:`documentation-trait` to the +``smithy.example#MyString`` shape: .. tabs:: .. code-tab:: smithy + $version: "1.1" namespace smithy.example apply MyString @documentation("This is my string!") - apply MyString @length(min: 1, max: 10) .. code-tab:: json { - "smithy": "1.0", + "smithy": "1.1", + "shapes": { + "smithy.example#MyString": { + "type": "apply", + "traits": { + "smithy.api#documentation": "This is my string!" + } + } + } + } + +Multiple traits can be applied to the same shape using a block apply +statement. The following example applies the :ref:`documentation-trait` +and :ref:`length-trait` to the ``smithy.example#MyString`` shape: + +.. tabs:: + + .. code-tab:: smithy + + $version: "1.1" + namespace smithy.example + + apply MyString { + @documentation("This is my string!") + @length(min: 1, max: 10) + } + + .. code-tab:: json + + { + "smithy": "1.1", "shapes": { "smithy.example#MyString": { "type": "apply", @@ -1525,6 +1557,7 @@ Traits can be applied to members too: .. code-block:: smithy + $version: "1.1" namespace smithy.example apply MyStructure$foo @documentation("Structure member documentation") diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/loader/IdlModelParser.java b/smithy-model/src/main/java/software/amazon/smithy/model/loader/IdlModelParser.java index 92b55d49a59..c0d813773c6 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/loader/IdlModelParser.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/loader/IdlModelParser.java @@ -667,12 +667,22 @@ private void parseApplyStatement() { String name = ParserUtils.parseShapeId(this); ws(); - TraitEntry traitEntry = IdlTraitParser.parseTraitValue(this); + // Account for singular or block apply statements. + List traitsToApply; + if (peek() == '{') { + expect('{'); + ws(); + traitsToApply = IdlTraitParser.parseTraits(this); + expect('}'); + } else { + traitsToApply = Collections.singletonList(IdlTraitParser.parseTraitValue(this)); + } // First, resolve the targeted shape. modelFile.addForwardReference(name, id -> { - // Next, resolve the trait ID. - onDeferredTrait(id, traitEntry.traitName, traitEntry.value, traitEntry.isAnnotation); + for (TraitEntry traitEntry : traitsToApply) { + onDeferredTrait(id, traitEntry.traitName, traitEntry.value, traitEntry.isAnnotation); + } }); // Clear out any errantly captured pending docs. diff --git a/smithy-model/src/test/resources/software/amazon/smithy/model/loader/invalid/apply/apply-block-missing-closing.smithy b/smithy-model/src/test/resources/software/amazon/smithy/model/loader/invalid/apply/apply-block-missing-closing.smithy new file mode 100644 index 00000000000..fcb753915ea --- /dev/null +++ b/smithy-model/src/test/resources/software/amazon/smithy/model/loader/invalid/apply/apply-block-missing-closing.smithy @@ -0,0 +1,6 @@ +// Parse error at line 7, column 1 near ``: Expected: '}' +$version: "1.1" +namespace com.foo + +apply SomeShape { + @deprecated diff --git a/smithy-model/src/test/resources/software/amazon/smithy/model/loader/invalid/apply-missing-trait-value.smithy b/smithy-model/src/test/resources/software/amazon/smithy/model/loader/invalid/apply/apply-missing-trait-value.smithy similarity index 100% rename from smithy-model/src/test/resources/software/amazon/smithy/model/loader/invalid/apply-missing-trait-value.smithy rename to smithy-model/src/test/resources/software/amazon/smithy/model/loader/invalid/apply/apply-missing-trait-value.smithy diff --git a/smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply/apply-block-empty.json b/smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply/apply-block-empty.json new file mode 100644 index 00000000000..5d0783422b7 --- /dev/null +++ b/smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply/apply-block-empty.json @@ -0,0 +1,13 @@ +{ + "smithy": "1.1", + "shapes": { + "smithy.example#Foo": { + "type": "structure", + "members": { + "baz": { + "target": "smithy.api#String" + } + } + } + } +} diff --git a/smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply/apply-block-empty.smithy b/smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply/apply-block-empty.smithy new file mode 100644 index 00000000000..d9bd2df3c90 --- /dev/null +++ b/smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply/apply-block-empty.smithy @@ -0,0 +1,9 @@ +$version: "1.1" +namespace smithy.example + +structure Foo { + baz: String, +} + +// Block apply statements may be empty. +apply Foo$baz {} diff --git a/smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply-statements.json b/smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply/apply-statements.json similarity index 94% rename from smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply-statements.json rename to smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply/apply-statements.json index 7d0dcc52458..1e8b169548f 100644 --- a/smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply-statements.json +++ b/smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply/apply-statements.json @@ -1,5 +1,5 @@ { - "smithy": "1.0", + "smithy": "1.1", "shapes": { "smithy.example#Foo": { "type": "structure", diff --git a/smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply-statements.smithy b/smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply/apply-statements.smithy similarity index 85% rename from smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply-statements.smithy rename to smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply/apply-statements.smithy index e9b074736f0..c4c5eda9089 100644 --- a/smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply-statements.smithy +++ b/smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply/apply-statements.smithy @@ -1,3 +1,4 @@ +$version: "1.1" namespace smithy.example structure Foo { diff --git a/smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply/apply-with-whitespace.json b/smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply/apply-with-whitespace.json new file mode 100644 index 00000000000..47c90a96eb7 --- /dev/null +++ b/smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply/apply-with-whitespace.json @@ -0,0 +1,18 @@ +{ + "smithy": "1.1", + "shapes": { + "smithy.example#Foo": { + "type": "structure", + "members": { + "baz": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "Hi", + "smithy.api#sensitive": {}, + "smithy.api#deprecated": {} + } + } + } + } + } +} diff --git a/smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply/apply-with-whitespace.smithy b/smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply/apply-with-whitespace.smithy new file mode 100644 index 00000000000..6f56601bc31 --- /dev/null +++ b/smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply/apply-with-whitespace.smithy @@ -0,0 +1,14 @@ +$version: "1.1" +namespace smithy.example + +structure Foo { + baz: String, +} + +apply Foo$baz{@documentation("Hi") @sensitive + + + + + + @deprecated} diff --git a/smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply/block-apply-statement.json b/smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply/block-apply-statement.json new file mode 100644 index 00000000000..47c90a96eb7 --- /dev/null +++ b/smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply/block-apply-statement.json @@ -0,0 +1,18 @@ +{ + "smithy": "1.1", + "shapes": { + "smithy.example#Foo": { + "type": "structure", + "members": { + "baz": { + "target": "smithy.api#String", + "traits": { + "smithy.api#documentation": "Hi", + "smithy.api#sensitive": {}, + "smithy.api#deprecated": {} + } + } + } + } + } +} diff --git a/smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply/block-apply-statement.smithy b/smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply/block-apply-statement.smithy new file mode 100644 index 00000000000..2702b9860b5 --- /dev/null +++ b/smithy-model/src/test/resources/software/amazon/smithy/model/loader/valid/apply/block-apply-statement.smithy @@ -0,0 +1,12 @@ +$version: "1.1" +namespace smithy.example + +structure Foo { + baz: String, +} + +apply Foo$baz { + @documentation("Hi") + @sensitive + @deprecated +}