use std::collections::HashMap;
use crate::validator::json_schema::{
self, ActionEntityUID, ActionType, ApplySpec, AttributesOrContext, CommonType, EntityType,
EntityTypeKind, Fragment, NamespaceDefinition, RecordType, StandardEntityType, Type,
TypeOfAttribute, TypeVariant,
};
use crate::validator::ValidatorSchema;
use crate::validator::{schema_errors::JsonDeserializationError, RawName, SchemaError};
use super::json_schema as compat;
use crate::extensions::Extensions;
use crate::{
ast::{Name, UnreservedId},
est::Annotations,
FromNormalizedStr,
};
use itertools::Itertools;
impl ValidatorSchema {
pub fn from_deprecated_json_value(
json: serde_json::Value,
extensions: &Extensions<'_>,
) -> Result<Self, SchemaError> {
Self::from_schema_frag(
json_schema::Fragment::<RawName>::from_deprecated_json_value(json)?,
extensions,
)
}
pub fn from_deprecated_json_str(
json: &str,
extensions: &Extensions<'_>,
) -> Result<Self, SchemaError> {
Self::from_schema_frag(
json_schema::Fragment::<RawName>::from_deprecated_json_str(json)?,
extensions,
)
}
pub fn from_deprecated_json_file(
file: impl std::io::Read,
extensions: &Extensions<'_>,
) -> Result<Self, SchemaError> {
Self::from_schema_frag(
json_schema::Fragment::<RawName>::from_deprecated_json_file(file)?,
extensions,
)
}
}
impl Fragment<RawName> {
pub fn from_deprecated_json_value(json: serde_json::Value) -> Result<Self, SchemaError> {
let compat: compat::SchemaFragment = serde_json::from_value(json).map_err(|e| {
SchemaError::JsonDeserialization(JsonDeserializationError::new(e, None))
})?;
compat
.try_into()
.map_err(|e| SchemaError::JsonDeserialization(JsonDeserializationError::new(e, None)))
}
pub fn from_deprecated_json_str(json: &str) -> Result<Self, SchemaError> {
let compat: compat::SchemaFragment = serde_json::from_str(json).map_err(|e| {
SchemaError::JsonDeserialization(JsonDeserializationError::new(e, Some(json)))
})?;
compat
.try_into()
.map_err(|e| SchemaError::JsonDeserialization(JsonDeserializationError::new(e, None)))
}
pub fn from_deprecated_json_file(file: impl std::io::Read) -> Result<Self, SchemaError> {
let compat: compat::SchemaFragment = serde_json::from_reader(file).map_err(|e| {
SchemaError::JsonDeserialization(JsonDeserializationError::new(e, None))
})?;
compat
.try_into()
.map_err(|e| SchemaError::JsonDeserialization(JsonDeserializationError::new(e, None)))
}
}
impl TryFrom<compat::SchemaFragment> for Fragment<RawName> {
type Error = serde_json::Error;
fn try_from(value: compat::SchemaFragment) -> Result<Self, Self::Error> {
Ok(Self(
value
.0
.into_iter()
.map(|(name, nsdef)| -> Result<_, Self::Error> {
let name: Option<Name> = if name.is_empty() {
None
} else {
Some(Name::from_normalized_str(&name).map_err(|err| {
serde::de::Error::custom(format!("invalid namespace `{name}`: {err}"))
})?)
};
Ok((name, nsdef.try_into()?))
})
.try_collect()?,
))
}
}
impl TryFrom<compat::NamespaceDefinition> for NamespaceDefinition<RawName> {
type Error = serde_json::Error;
fn try_from(value: compat::NamespaceDefinition) -> Result<Self, Self::Error> {
Ok(Self {
common_types: value
.common_types
.into_iter()
.map(|(id, ty)| -> Result<_, Self::Error> { Ok((id, ty.try_into()?)) })
.try_collect()?,
entity_types: value
.entity_types
.into_iter()
.map(|(id, ety)| -> Result<_, Self::Error> { Ok((id, ety.try_into()?)) })
.try_collect()?,
actions: value
.actions
.into_iter()
.map(|(id, aty)| aty.try_into().map(|aty| (id, aty)))
.try_collect()?,
annotations: Annotations::new(),
#[cfg(feature = "extended-schema")]
loc: None,
})
}
}
impl TryFrom<compat::SchemaType> for CommonType<RawName> {
type Error = serde_json::Error;
fn try_from(value: compat::SchemaType) -> Result<Self, Self::Error> {
Ok(Self {
ty: value.try_into()?,
annotations: Annotations::new(),
loc: None,
})
}
}
impl TryFrom<compat::SchemaType> for Type<RawName> {
type Error = serde_json::Error;
fn try_from(value: compat::SchemaType) -> Result<Self, Self::Error> {
Ok(match value {
compat::SchemaType::Type(schema_type_variant) => Self::Type {
ty: schema_type_variant.try_into()?,
loc: None,
},
compat::SchemaType::TypeDef { type_name } => Self::CommonTypeRef {
type_name: RawName::from_normalized_str(&type_name).map_err(|err| {
serde::de::Error::custom(format!("invalid common type `{type_name}`: {err}"))
})?,
loc: None,
},
})
}
}
impl TryFrom<compat::SchemaTypeVariant> for TypeVariant<RawName> {
type Error = serde_json::Error;
fn try_from(value: compat::SchemaTypeVariant) -> Result<Self, Self::Error> {
Ok(match value {
compat::SchemaTypeVariant::String => Self::String,
compat::SchemaTypeVariant::Long => Self::Long,
compat::SchemaTypeVariant::Boolean => Self::Boolean,
compat::SchemaTypeVariant::Set { element } => Self::Set {
element: Box::new((*element).try_into()?),
},
compat::SchemaTypeVariant::Record {
attributes,
additional_attributes,
} => Self::Record(RecordType {
attributes: attributes
.into_iter()
.map(|(id, ty)| ty.try_into().map(|ty| (id, ty)))
.try_collect()?,
additional_attributes,
}),
compat::SchemaTypeVariant::Entity { name } => Self::Entity {
name: RawName::from_normalized_str(&name).map_err(|err| {
serde::de::Error::custom(format!("invalid entity type `{name}`: {err}"))
})?,
},
compat::SchemaTypeVariant::Extension { name } => Self::Extension {
name: UnreservedId::from_normalized_str(&name).map_err(|err| {
serde::de::Error::custom(format!("invalid extension type `{name}`: {err}"))
})?,
},
})
}
}
impl TryFrom<compat::EntityType> for EntityType<RawName> {
type Error = serde_json::Error;
fn try_from(value: compat::EntityType) -> Result<Self, Self::Error> {
Ok(Self {
kind: EntityTypeKind::Standard(StandardEntityType {
member_of_types: value.member_of_types,
shape: value.shape.try_into()?,
tags: None,
}),
annotations: Annotations::new(),
loc: None,
})
}
}
impl TryFrom<compat::ActionType> for ActionType<RawName> {
type Error = serde_json::Error;
fn try_from(value: compat::ActionType) -> Result<Self, Self::Error> {
Ok(Self {
attributes: value.attributes.map(|_attrs| HashMap::from([])),
applies_to: value
.applies_to
.map(|applies_to| applies_to.try_into())
.transpose()?,
member_of: value
.member_of
.map(|member_of| {
member_of
.into_iter()
.map(|aid| aid.try_into())
.try_collect()
})
.transpose()?,
annotations: Annotations::new(),
loc: None,
#[cfg(feature = "extended-schema")]
defn_loc: None,
})
}
}
impl TryFrom<compat::AttributesOrContext> for AttributesOrContext<RawName> {
type Error = serde_json::Error;
fn try_from(value: compat::AttributesOrContext) -> Result<Self, Self::Error> {
Ok(Self(value.0.try_into()?))
}
}
impl TryFrom<compat::ApplySpec> for ApplySpec<RawName> {
type Error = serde_json::Error;
fn try_from(value: compat::ApplySpec) -> Result<Self, Self::Error> {
let Some(resource_types) = value.resource_types else {
return Err(serde::de::Error::missing_field("resourceTypes"));
};
let Some(principal_types) = value.principal_types else {
return Err(serde::de::Error::missing_field("principalTypes"));
};
Ok(Self {
resource_types,
principal_types,
context: value.context.try_into()?,
})
}
}
impl TryFrom<compat::ActionEntityUID> for ActionEntityUID<RawName> {
type Error = serde_json::Error;
fn try_from(value: compat::ActionEntityUID) -> Result<Self, Self::Error> {
Ok(Self {
id: value.id,
ty: value.ty,
#[cfg(feature = "extended-schema")]
loc: None,
})
}
}
impl TryFrom<compat::TypeOfAttribute> for TypeOfAttribute<RawName> {
type Error = serde_json::Error;
fn try_from(value: compat::TypeOfAttribute) -> Result<Self, Self::Error> {
Ok(Self {
ty: value.ty.try_into()?,
annotations: Annotations::new(),
required: value.required,
#[cfg(feature = "extended-schema")]
loc: None,
})
}
}