use json_syntax::JsonValue;
use rdf_syntax::Id;
use crate::{
JsonLdBacktraceBuilder, JsonLdDirection, JsonLdError, JsonLdIndexed, JsonLdIndexedObject,
JsonLdLangString, JsonLdLenient, JsonLdLocatedError, JsonLdNullable, JsonLdObject, JsonLdTerm,
JsonLdValue, JsonLdWarning,
context::RawJsonLdProcessedContext,
object::{JsonLdLiteralValue, value::JsonLdLiteralType},
syntax::JsonLdKeyword,
};
use super::{ExpandedEntry, Expander};
pub type ValueExpansionResult = Result<Option<JsonLdIndexedObject>, JsonLdLocatedError>;
impl<'a> Expander<'a> {
pub fn expand_value(
&self,
mut warn: impl FnMut(JsonLdWarning),
input_type: Option<JsonLdTerm>,
type_scoped_context: &RawJsonLdProcessedContext,
expanded_entries: Vec<ExpandedEntry>,
value_entry: &JsonValue,
location: JsonLdBacktraceBuilder<'_>,
) -> ValueExpansionResult {
let mut is_json = input_type
.as_ref()
.map(|t| *t == JsonLdTerm::Keyword(JsonLdKeyword::Json))
.unwrap_or(false);
let mut ty = None;
let mut index = None;
let mut language = None;
let mut direction = None;
for ExpandedEntry {
key,
expanded_key,
value,
} in expanded_entries
{
let entry_loc = location.object_value(key);
match expanded_key {
JsonLdTerm::Keyword(JsonLdKeyword::Language) => {
if let Some(value) = value.as_str() {
if value != "@none" {
language = Some(value.to_owned());
}
} else {
return Err(JsonLdError::InvalidLanguageTaggedString.at(entry_loc));
}
}
JsonLdTerm::Keyword(JsonLdKeyword::Direction) => {
if let Some(value) = value.as_str() {
if let Ok(value) = JsonLdDirection::try_from(value) {
direction = Some(value);
} else {
return Err(JsonLdError::InvalidBaseDirection.at(entry_loc));
}
} else {
return Err(JsonLdError::InvalidBaseDirection.at(entry_loc));
}
}
JsonLdTerm::Keyword(JsonLdKeyword::Index) => {
if let Some(value) = value.as_str() {
index = Some(value.to_string())
} else {
return Err(JsonLdError::InvalidIndexValue.at(entry_loc));
}
}
JsonLdTerm::Keyword(JsonLdKeyword::Type) => {
if let Some(ty_value) = value.as_str() {
let expanded_ty = type_scoped_context.expand_iri(
JsonLdNullable::Some(ty_value.into()),
true,
true,
);
match expanded_ty {
JsonLdTerm::Keyword(JsonLdKeyword::Json) => {
is_json = true;
}
JsonLdTerm::Id(JsonLdLenient::Valid(Id::Iri(expanded_ty))) => {
is_json = false;
ty = Some(expanded_ty)
}
_ => return Err(JsonLdError::InvalidTypedValue.at(entry_loc)),
}
} else {
return Err(JsonLdError::InvalidTypedValue.at(entry_loc));
}
}
JsonLdTerm::Keyword(JsonLdKeyword::Value) => (),
_ => {
return Err(JsonLdError::InvalidValueObject.at(entry_loc));
}
}
}
if is_json {
if language.is_some() || direction.is_some() {
return Err(JsonLdError::InvalidValueObject.at(location));
}
return Ok(Some(JsonLdIndexed::new(
JsonLdObject::Value(JsonLdValue::Literal(JsonLdLiteralValue::json(
value_entry.clone(),
))),
index,
)));
}
let result_value = match value_entry {
JsonValue::Null
| JsonValue::String(_)
| JsonValue::Number(_)
| JsonValue::Boolean(_) => value_entry.clone(),
_ => {
return Err(JsonLdError::InvalidValueObjectValue.at(location));
}
};
if result_value.is_null() {
return Ok(None);
}
if language.is_some() || direction.is_some() {
if ty.is_some() {
return Err(JsonLdError::InvalidValueObject.at(location));
}
if let JsonValue::String(s) = result_value {
let lang = match language {
Some(language) => {
let (language, error) = JsonLdLenient::from_string(language);
if let Some(error) = error {
warn(JsonLdWarning::MalformedLanguageTag(
language.to_string(),
error,
))
}
Some(language)
}
None => None,
};
return match JsonLdLangString::new(s, lang, direction) {
Ok(result) => Ok(Some(JsonLdIndexed::new(
JsonLdObject::Value(JsonLdValue::LangString(result)),
index,
))),
Err(_) => Err(JsonLdError::InvalidLanguageTaggedValue.at(location)),
};
} else {
return Err(JsonLdError::InvalidLanguageTaggedValue.at(location));
}
}
Ok(Some(JsonLdIndexed::new(
JsonLdObject::Value(JsonLdValue::Literal(JsonLdLiteralValue::new(
result_value,
ty.map(JsonLdLiteralType::Iri),
))),
index,
)))
}
}