Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
haydenbaker committed Dec 20, 2024
1 parent 42c09de commit bba14e1
Showing 1 changed file with 105 additions and 56 deletions.
Original file line number Diff line number Diff line change
@@ -1,18 +1,7 @@
/*
* Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/

package software.amazon.smithy.model.validation.validators;

import java.util.ArrayList;
Expand Down Expand Up @@ -60,44 +49,79 @@ private List<ValidationEvent> validateResource(Model model, ResourceShape resour
Set<String> propertiesInOperations = new TreeSet<>();
PropertyBindingIndex propertyBindingIndex = PropertyBindingIndex.of(model);

processLifecycleOperationProperties(model, resource, "put", resource.getPut(),
propertyBindingIndex, propertiesInOperations, events);
processLifecycleOperationProperties(model, resource, "create", resource.getCreate(),
propertyBindingIndex, propertiesInOperations, events);
processLifecycleOperationProperties(model, resource, "read", resource.getRead(),
propertyBindingIndex, propertiesInOperations, events);
processLifecycleOperationProperties(model, resource, "update", resource.getUpdate(),
propertyBindingIndex, propertiesInOperations, events);
processLifecycleOperationProperties(model, resource, "delete", resource.getDelete(),
propertyBindingIndex, propertiesInOperations, events);
processLifecycleOperationProperties(model,
resource,
"put",
resource.getPut(),
propertyBindingIndex,
propertiesInOperations,
events);
processLifecycleOperationProperties(model,
resource,
"create",
resource.getCreate(),
propertyBindingIndex,
propertiesInOperations,
events);
processLifecycleOperationProperties(model,
resource,
"read",
resource.getRead(),
propertyBindingIndex,
propertiesInOperations,
events);
processLifecycleOperationProperties(model,
resource,
"update",
resource.getUpdate(),
propertyBindingIndex,
propertiesInOperations,
events);
processLifecycleOperationProperties(model,
resource,
"delete",
resource.getDelete(),
propertyBindingIndex,
propertiesInOperations,
events);
for (ShapeId operationId : resource.getOperations()) {
processLifecycleOperationProperties(model, resource, operationId.getName(), Optional.of(operationId),
propertyBindingIndex, propertiesInOperations, events);
processLifecycleOperationProperties(model,
resource,
operationId.getName(),
Optional.of(operationId),
propertyBindingIndex,
propertiesInOperations,
events);
}

Set<String> definedProperties = new HashSet<>(resource.getProperties().keySet());
definedProperties.removeAll(propertiesInOperations);
for (String propertyNotInLifecycleOp : definedProperties) {
events.add(error(resource, String.format("Resource property `%s` is not used in the input or output"
+ " of create or an instance operation.", propertyNotInLifecycleOp)));
events.add(error(resource,
String.format("Resource property `%s` is not used in the input or output"
+ " of create or an instance operation.", propertyNotInLifecycleOp)));
}

return events;
}

private void processLifecycleOperationProperties(
Model model,
ResourceShape resource,
String name,
Optional<ShapeId> operationShapeId,
PropertyBindingIndex propertyBindingIndex,
Set<String> propertiesInOperations,
List<ValidationEvent> events
Model model,
ResourceShape resource,
String name,
Optional<ShapeId> operationShapeId,
PropertyBindingIndex propertyBindingIndex,
Set<String> propertiesInOperations,
List<ValidationEvent> events
) {
operationShapeId.flatMap(model::getShape).flatMap(Shape::asOperationShape).ifPresent(operation -> {
propertiesInOperations.addAll(getAllOperationProperties(propertyBindingIndex, operation));
validateOperationInputOutput(model, propertyBindingIndex, resource, operation,
name, events);
validateOperationInputOutput(model,
propertyBindingIndex,
resource,
operation,
name,
events);
});
}

Expand Down Expand Up @@ -143,13 +167,20 @@ private void validateOperationOutput(
Map<String, Set<MemberShape>> propertyToMemberMappings = new TreeMap<>();
IdentifierBindingIndex identifierBindingIndex = IdentifierBindingIndex.of(model);
Set<String> identifierMembers = new HashSet<>(identifierBindingIndex
.getOperationOutputBindings(resource, operation).values());
.getOperationOutputBindings(resource, operation)
.values());

Shape shape = propertyBindingIndex.getOutputPropertiesShape(operation);
for (MemberShape member : shape.members()) {
if (propertyBindingIndex.isMemberShapeProperty(member)) {
validateMember(events, lifecycleOperationName, propertyBindingIndex, resource, member,
identifierMembers, properties, propertyToMemberMappings);
validateMember(events,
lifecycleOperationName,
propertyBindingIndex,
resource,
member,
identifierMembers,
properties,
propertyToMemberMappings);
}
}
validateConflictingProperties(events, shape, propertyToMemberMappings);
Expand All @@ -167,13 +198,20 @@ private void validateOperationInput(
Map<String, Set<MemberShape>> propertyToMemberMappings = new TreeMap<>();
IdentifierBindingIndex identifierBindingIndex = IdentifierBindingIndex.of(model);
Set<String> identifierMembers = new HashSet<>(identifierBindingIndex
.getOperationOutputBindings(resource, operation).values());
.getOperationOutputBindings(resource, operation)
.values());

Shape shape = propertyBindingIndex.getInputPropertiesShape(operation);
for (MemberShape member : shape.members()) {
if (propertyBindingIndex.isMemberShapeProperty(member)) {
validateMember(events, lifecycleOperationName, propertyBindingIndex, resource, member,
identifierMembers, properties, propertyToMemberMappings);
validateMember(events,
lifecycleOperationName,
propertyBindingIndex,
resource,
member,
identifierMembers,
properties,
propertyToMemberMappings);
}
}
validateConflictingProperties(events, shape, propertyToMemberMappings);
Expand All @@ -186,11 +224,14 @@ private void validateConflictingProperties(
) {
for (Map.Entry<String, Set<MemberShape>> entry : propertyToMemberMappings.entrySet()) {
if (entry.getValue().size() > 1) {
events.add(error(shape, String.format(
"This shape contains members with conflicting resource property names that resolve to '%s': %s",
entry.getKey(),
entry.getValue().stream().map(MemberShape::getMemberName)
.collect(Collectors.joining(", ")))));
events.add(error(shape,
String.format(
"This shape contains members with conflicting resource property names that resolve to '%s': %s",
entry.getKey(),
entry.getValue()
.stream()
.map(MemberShape::getMemberName)
.collect(Collectors.joining(", ")))));
}
}
}
Expand All @@ -210,17 +251,25 @@ private void validateMember(
if (properties.containsKey(propertyName)) {
if (!properties.get(propertyName).equals(member.getTarget())) {
ShapeId expectedTarget = properties.get(propertyName);
events.add(error(member, String.format(
"This member must target `%s`. This member is used as part of the `%s` operation of the `%s` "
+ "resource and conflicts with its `%s` resource property.",
expectedTarget, lifecycleOperationName,
resource.getId(), propertyName)));
events.add(error(member,
String.format(
"This member must target `%s`. This member is used as part of the `%s` operation of the `%s` "
+ "resource and conflicts with its `%s` resource property.",
expectedTarget,
lifecycleOperationName,
resource.getId(),
propertyName)));
}
} else if (!identifierMembers.contains(member.getMemberName())) {
events.add(error(member, String.format("Member `%s` does not target a property or identifier for resource "
+ "`%s`. If it is an identifier, apply the `%s` trait. If it is a property, apply the `%s` trait. "
+ "If it is neither, apply the `%s` trait.", member.getMemberName(), resource.getId().toString(),
ResourceIdentifierTrait.ID, PropertyTrait.ID, NotPropertyTrait.ID)));
events.add(error(member,
String.format("Member `%s` does not target a property or identifier for resource "
+ "`%s`. If it is an identifier, apply the `%s` trait. If it is a property, apply the `%s` trait. "
+ "If it is neither, apply the `%s` trait.",
member.getMemberName(),
resource.getId().toString(),
ResourceIdentifierTrait.ID,
PropertyTrait.ID,
NotPropertyTrait.ID)));
}
}
}

0 comments on commit bba14e1

Please sign in to comment.