///|
fn enum_values(
model : @smithy.Model,
shape : @smithy.Shape,
) -> Array[@smithy.NodeValue]? {
if shape.trait_value("smithy.api#enum") is Some(Array(values)) {
return Some(values)
}
if shape.body is Enum(ids) {
let values = []
for id in ids {
if model.shapes.get(id) is Some(member_shape) &&
member_shape.trait_value("smithy.api#enumValue") is Some(value) {
let definition : Map[String, @smithy.NodeValue] = {
"value": value,
"name": String(id.member_name().unwrap()),
}
values.push(@smithy.NodeValue::Object(definition))
}
}
return Some(values)
}
None
}
///|
fn enum_changes(
d : Differences,
change : ShapeChange,
events : Array[ValidationEvent],
) -> Unit {
let a = change.old_shape
let b = change.new_shape
guard enum_values(d.old_model, a) is Some(old_values) &&
enum_values(d.new_model, b) is Some(new_values) &&
old_values != new_values else {
return
}
let mut old_end = old_values.length() - 1
for index, value in old_values {
let new_value = new_values
.iter()
.find_first(v => field(Some(v), "value") == field(Some(value), "value"))
let text = string(field(Some(value), "value")).unwrap_or("")
if new_value == None {
emit(
events,
"ChangedEnumTrait.Removed." + index.to_string(),
"ERROR",
b,
"Enum value " + tick(text) + " was removed",
)
old_end = old_end - 1
} else if field(Some(value), "name") != field(new_value, "name") {
emit(
events,
"ChangedEnumTrait.NameChanged." + index.to_string(),
"ERROR",
b,
"Enum `name` changed from " +
tick(string(field(Some(value), "name")).unwrap_or("null")) +
" to " +
tick(string(field(new_value, "name")).unwrap_or("null")) +
" for the " +
tick(text) +
" value",
)
}
}
for index, value in new_values {
if !old_values
.iter()
.any(v => field(Some(v), "value") == field(Some(value), "value")) {
let text = string(field(Some(value), "value")).unwrap_or("")
if index <= old_end {
emit(
events,
"ChangedEnumTrait.OrderChanged." + index.to_string(),
"ERROR",
b,
"Enum value " +
tick(text) +
" was inserted before the end of the list of existing values. This can cause compatibility issues when ordinal values are used for iteration, serialization, etc.",
)
old_end = old_end + 1
} else {
emit(
events,
"ChangedEnumTrait.Appended." + index.to_string(),
"NOTE",
b,
"Enum value " + tick(text) + " was appended",
)
}
}
}
}