in smithy-model/src/main/java/software/amazon/smithy/model/validation/validators/PaginatedTraitValidator.java [118:185]
private List<ValidationEvent> validateMember(
OperationIndex opIndex,
Model model,
ServiceShape service,
OperationShape operation,
PaginatedTrait trait,
PropertyValidator validator
) {
String prefix = service != null ? "When bound within the `" + service.getId() + "` service, " : "";
String memberPath = validator.getMemberPath(opIndex, operation, trait).orElse(null);
if (memberPath == null) {
return service != null && validator.isRequiredToBePresent()
? Collections.singletonList(error(operation, trait, String.format(
"%spaginated trait `%s` is not configured", prefix, validator.propertyName())))
: Collections.emptyList();
}
if (!validator.pathsAllowed() && memberPath.contains(".")) {
return Collections.singletonList(error(operation, trait, String.format(
"%spaginated trait `%s` does not allow path values", prefix, validator.propertyName()
)));
}
MemberShape member = validator.getMember(model, opIndex, operation, trait).orElse(null);
if (member == null) {
return Collections.singletonList(error(operation, trait, String.format(
"%spaginated trait `%s` targets a member `%s` that does not exist",
prefix, validator.propertyName(), memberPath)));
}
List<ValidationEvent> events = new ArrayList<>();
if (validator.mustBeOptional() && member.isRequired()) {
events.add(error(operation, trait, String.format(
"%spaginated trait `%s` member `%s` must not be required",
prefix, validator.propertyName(), member.getMemberName())));
}
Shape target = model.getShape(member.getTarget()).orElse(null);
if (target != null) {
if (!validator.validTargets().contains(target.getType())) {
events.add(error(operation, trait, String.format(
"%spaginated trait `%s` member `%s` targets a %s shape, but must target one of "
+ "the following: [%s]",
prefix, validator.propertyName(), member.getId().getName(), target.getType(),
ValidationUtils.tickedList(validator.validTargets()))));
}
if (validator.dangerTargets().contains(target.getType())) {
Set<ShapeType> preferredTargets = new TreeSet<>(validator.validTargets());
preferredTargets.removeAll(validator.dangerTargets());
events.add(danger(operation, trait, String.format(
"%spaginated trait `%s` member `%s` targets a %s shape, but this is not recommended. "
+ "One of [%s] SHOULD be targeted.",
prefix, validator.propertyName(), member.getId().getName(), target.getType(),
ValidationUtils.tickedList(preferredTargets))));
}
}
if (validator.pathsAllowed() && PATH_PATTERN.split(memberPath).length > 2) {
events.add(warning(operation, trait, String.format(
"%spaginated trait `%s` contains a path with more than two parts, which can make your API "
+ "cumbersome to use",
prefix, validator.propertyName()
)));
}
return events;
}