use crate::php_type::PhpType;
fn resolve_shape_keys(entries: &[crate::php_type::ShapeEntry]) -> Vec<crate::php_type::ShapeEntry> {
let mut result = Vec::with_capacity(entries.len());
let mut implicit_index: u32 = 0;
for entry in entries {
let key = match &entry.key {
Some(k) => Some(k.clone()),
None => {
let k = implicit_index.to_string();
implicit_index += 1;
Some(k)
}
};
result.push(crate::php_type::ShapeEntry {
key,
value_type: entry.value_type.clone(),
optional: entry.optional,
});
}
result
}
fn unwrap_array_shape(ty: &PhpType) -> Option<&[crate::php_type::ShapeEntry]> {
match ty {
PhpType::ArrayShape(entries) => Some(entries),
PhpType::Nullable(inner) => unwrap_array_shape(inner),
_ => None,
}
}
fn unwrap_object_shape(ty: &PhpType) -> Option<&[crate::php_type::ShapeEntry]> {
match ty {
PhpType::ObjectShape(entries) => Some(entries),
PhpType::Nullable(inner) => unwrap_object_shape(inner),
PhpType::Intersection(members) => members.iter().find_map(|m| unwrap_object_shape(m)),
_ => None,
}
}
pub fn parse_array_shape_typed(ty: &PhpType) -> Option<Vec<crate::php_type::ShapeEntry>> {
let entries = unwrap_array_shape(ty)?;
Some(resolve_shape_keys(entries))
}
pub fn extract_array_shape_value_type_typed(ty: &PhpType, key: &str) -> Option<PhpType> {
let entries = parse_array_shape_typed(ty)?;
entries
.into_iter()
.find(|e| e.key.as_deref() == Some(key))
.map(|e| e.value_type)
}
pub fn parse_object_shape_typed(ty: &PhpType) -> Option<Vec<crate::php_type::ShapeEntry>> {
let entries = unwrap_object_shape(ty)?;
Some(resolve_shape_keys(entries))
}
pub fn is_object_shape_typed(ty: &PhpType) -> bool {
ty.is_object_shape()
}
pub fn extract_object_shape_property_type_typed(ty: &PhpType, prop: &str) -> Option<PhpType> {
let entries = parse_object_shape_typed(ty)?;
entries
.into_iter()
.find(|e| e.key.as_deref() == Some(prop))
.map(|e| e.value_type)
}