-
Notifications
You must be signed in to change notification settings - Fork 243
Add @conditions, smithy-model-jmespath, NodeValidationPlugin SPI #2935
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 7 commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
b8222b9
Add @conditions, smithy-model-jmespath, NodeValidationPlugin SPI
robin-aws 3682b03
Feature
robin-aws c733e5a
Make @conditions a map instead of a list
robin-aws 5293120
Apply suggestions from code review
robin-aws 53307c0
Fix build after PR edits
robin-aws f0d555e
PR feedback
robin-aws 8644b15
A bit more Javadoc
robin-aws 739c82e
Fix breaks from removing getParsedExpression()
robin-aws 9346581
description -> documentation, fix tests
robin-aws 9fdfe28
Wafer-thin javadoc
robin-aws 576b4ae
smithydoc
robin-aws 9bd77ed
Fix weird autoformat
robin-aws 58632cb
Update smithy-contract-traits/src/main/java/software/amazon/smithy/co…
robin-aws 5079293
Update smithy-contract-traits/src/main/java/software/amazon/smithy/co…
robin-aws fa27a72
Merge branch 'smithy-contracts-squashed' of github.com:robin-aws/smit…
robin-aws 16714fd
Make ShapeTypeFilters static finals where possible
robin-aws 9bf9f1c
shapeMatcher() -> shapeTypeFilter(), Javadoc on MemberAndShapeTraitPl…
robin-aws 8bce774
Second release note
robin-aws File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
7 changes: 7 additions & 0 deletions
7
.changes/next-release/feature-077b7f1cd574ee78042363f8d8c3afb20d56f081.json
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| { | ||
| "type": "feature", | ||
| "description": "Added the `@smithy.contracts#conditions` trait, available in the new `smithy-contract-traits` package. This trait defines restrictions on shape values using JMESPath expressions." , | ||
| "pull_requests": [ | ||
| "[#2935](https://github.com/smithy-lang/smithy/pull/2935)" | ||
| ] | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| .. _contract-traits: | ||
|
|
||
| =============== | ||
| Contract traits | ||
| =============== | ||
|
|
||
| Contract traits are used to further constrain the valid values and behaviors of a model. | ||
| Like constraint traits, contract traits are for validation only and SHOULD NOT | ||
| impact the types signatures of generated code. | ||
|
|
||
| -------------------------- | ||
| Contract trait enforcement | ||
| -------------------------- | ||
|
|
||
| Contract traits SHOULD NOT be directly enforced by default when serializing or deserializing. | ||
| These traits often express contracts using higher-level constructs and simpler but less efficient expressions. | ||
| Services will usually check these contracts outside of service frameworks in more efficient ways. | ||
|
|
||
| Contract traits are instead intended to be useful for generating tests | ||
| or applying static analysis to client or service code. | ||
|
|
||
| .. smithy-trait:: smithy.contracts#conditions | ||
| .. _conditions-trait: | ||
|
|
||
| -------------------- | ||
| ``conditions`` trait | ||
| -------------------- | ||
|
|
||
| Summary | ||
| Restricts shape values to those which satisfy the given JMESPath expressions. | ||
| Trait selector | ||
| ``:not(:test(service, operation, resource))`` | ||
|
|
||
| *Any shape other than services, operations, and resources* | ||
| Value type | ||
| ``map`` | ||
|
|
||
| The ``conditions`` trait is a map from condition names to ``Condition`` structures that contain | ||
| the following members: | ||
|
|
||
| .. list-table:: | ||
| :header-rows: 1 | ||
| :widths: 10 23 67 | ||
|
|
||
| * - Property | ||
| - Type | ||
| - Description | ||
| * - expression | ||
| - ``string`` | ||
| - **Required**. JMESPath expression that must evaluate to true. | ||
| * - description | ||
| - ``string`` | ||
| - **Required**. Description of the condition. Used in error messages when violated. | ||
|
|
||
| .. code-block:: smithy | ||
|
|
||
| @conditions({ | ||
| StartBeforeEnd: { | ||
| description: "The start time must be strictly less than the end time", | ||
| expression: "start < end" | ||
| } | ||
| }) | ||
| structure FetchLogsInput { | ||
| @required | ||
| start: Timestamp | ||
|
|
||
| @required | ||
| end: Timestamp | ||
| } | ||
|
|
||
| @conditions({ | ||
| NoKeywords: { | ||
| description: "The name cannot contain either 'id' or 'name', as these are reserved keywords" | ||
| expression: "!contains(@, 'id') && !contains(@, 'name')" | ||
| } | ||
| }) | ||
| string Name |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| /* | ||
| * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
| plugins { | ||
| id("smithy.module-conventions") | ||
| } | ||
|
|
||
| description = "This module provides Smithy traits for declaring contracts on models." | ||
|
|
||
| extra["displayName"] = "Smithy :: Contract Traits" | ||
| extra["moduleName"] = "software.amazon.smithy.contract.traits" | ||
|
|
||
| dependencies { | ||
| api(project(":smithy-model-jmespath")) | ||
| } |
142 changes: 142 additions & 0 deletions
142
smithy-contract-traits/src/main/java/software/amazon/smithy/contracts/Condition.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,142 @@ | ||
| /* | ||
| * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
| package software.amazon.smithy.contracts; | ||
|
|
||
| import software.amazon.smithy.jmespath.JmespathException; | ||
| import software.amazon.smithy.jmespath.JmespathExpression; | ||
| import software.amazon.smithy.model.FromSourceLocation; | ||
| import software.amazon.smithy.model.SourceException; | ||
| import software.amazon.smithy.model.SourceLocation; | ||
| import software.amazon.smithy.model.node.ExpectationNotMetException; | ||
| import software.amazon.smithy.model.node.Node; | ||
| import software.amazon.smithy.model.node.ToNode; | ||
| import software.amazon.smithy.utils.SmithyBuilder; | ||
| import software.amazon.smithy.utils.ToSmithyBuilder; | ||
|
|
||
| public final class Condition implements ToNode, ToSmithyBuilder<Condition>, FromSourceLocation { | ||
| private final SourceLocation sourceLocation; | ||
| private final String expressionText; | ||
| private final JmespathExpression expression; | ||
| private final String description; | ||
|
|
||
| private Condition(Builder builder) { | ||
| this.sourceLocation = SmithyBuilder.requiredState("sourceLocation", builder.sourceLocation); | ||
| this.expressionText = SmithyBuilder.requiredState("expression", builder.expression); | ||
| try { | ||
| this.expression = JmespathExpression.parse(expressionText); | ||
| } catch (JmespathException e) { | ||
| throw new SourceException( | ||
| "Invalid condition JMESPath expression: `" + expressionText + "`. " + e.getMessage(), | ||
| builder.sourceLocation); | ||
| } | ||
| this.description = SmithyBuilder.requiredState("description", builder.description); | ||
| } | ||
|
|
||
| @Override | ||
| public Node toNode() { | ||
| return Node.objectNodeBuilder() | ||
| .withMember("expression", Node.from(expressionText)) | ||
| .withMember("description", Node.from(description)) | ||
| .build(); | ||
| } | ||
|
|
||
| /** | ||
| * Creates a {@link Condition} from a {@link Node}. | ||
| * | ||
| * @param node Node to create the Condition from. | ||
| * @return Returns the created Condition. | ||
| * @throws ExpectationNotMetException if the given Node is invalid. | ||
| */ | ||
| public static Condition fromNode(Node node) { | ||
| Builder builder = builder().sourceLocation(node.getSourceLocation()); | ||
| node.expectObjectNode() | ||
| .expectStringMember("expression", builder::expression) | ||
| .expectStringMember("description", builder::description); | ||
| return builder.build(); | ||
| } | ||
|
|
||
| @Override | ||
| public SourceLocation getSourceLocation() { | ||
| return sourceLocation; | ||
| } | ||
|
|
||
| /** | ||
| * JMESPath expression that must evaluate to true. | ||
| */ | ||
| public JmespathExpression getExpression() { | ||
| return expression; | ||
| } | ||
|
|
||
| /** | ||
| * Description of the condition. Used in error messages when violated. | ||
| */ | ||
| public String getDescription() { | ||
| return description; | ||
| } | ||
|
|
||
| /** | ||
| * Creates a builder used to build a {@link Condition}. | ||
| */ | ||
| public SmithyBuilder<Condition> toBuilder() { | ||
robin-aws marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return builder() | ||
| .expression(expressionText) | ||
| .description(description); | ||
| } | ||
|
|
||
| /** | ||
| * Creates a builder used to build an equivalent {@link Condition}. | ||
robin-aws marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| */ | ||
| public static Builder builder() { | ||
| return new Builder(); | ||
| } | ||
|
|
||
| /** | ||
| * Builder for {@link Condition}. | ||
| */ | ||
| public static final class Builder implements SmithyBuilder<Condition> { | ||
| private SourceLocation sourceLocation; | ||
| private String expression; | ||
| private String description; | ||
|
|
||
| private Builder() {} | ||
|
|
||
| public Builder sourceLocation(SourceLocation sourceLocation) { | ||
| this.sourceLocation = sourceLocation; | ||
| return this; | ||
| } | ||
|
|
||
| public Builder expression(String expression) { | ||
| this.expression = expression; | ||
| return this; | ||
| } | ||
|
|
||
| public Builder description(String description) { | ||
| this.description = description; | ||
| return this; | ||
| } | ||
|
|
||
| @Override | ||
| public Condition build() { | ||
| return new Condition(this); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object other) { | ||
| if (other == this) { | ||
| return true; | ||
| } else if (!(other instanceof Condition)) { | ||
| return false; | ||
| } else { | ||
| Condition b = (Condition) other; | ||
| return toNode().equals(b.toNode()); | ||
| } | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| return toNode().hashCode(); | ||
| } | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.