use json_syntax::{JsonObject, JsonValue};
use mown::Mown;
use crate::{
JsonLdBacktraceBuilder, JsonLdLenient, JsonLdLocatedError, JsonLdTerm, JsonLdType, JsonLdValue,
algorithms::{
AsyncJsonLdEnvironment, AsyncProcessingEnvironmentRef,
context_processing::JsonLdContextProcessingOptions,
},
context::JsonLdContainer,
object::value::JsonLdLiteralType,
syntax::{JsonLdContainerItem, JsonLdKeyword},
};
use super::Compactor;
impl<'a> Compactor<'a> {
pub async fn compact_indexed_value_with(
&self,
env: &impl AsyncJsonLdEnvironment,
value: &JsonLdValue,
index: Option<&str>,
location: JsonLdBacktraceBuilder<'_>,
) -> Result<JsonValue, JsonLdLocatedError> {
let mut active_context = Mown::Borrowed(self.active_context);
if let Some(active_property) = self.active_property
&& let Some(active_property_definition) = active_context.get(active_property)
&& let Some(local_context) = active_property_definition.context()
{
let def_loc =
location.push_backtrace(active_property_definition.location().unwrap_or_default());
let scoped_context_loc = def_loc.object_value(JsonLdKeyword::Context);
active_context = Mown::Owned(
local_context
.process_with(
AsyncProcessingEnvironmentRef(env),
active_property_definition.base_url(),
active_context.as_ref(),
JsonLdContextProcessingOptions::from(self.options).with_override(),
scoped_context_loc,
)
.await?
.into_raw(),
)
}
let mut result = JsonObject::default();
let active_property_definition = match self.active_property {
Some(active_property) => active_context.get(active_property),
None => None,
};
let language = match active_property_definition {
Some(def) => match def.language() {
Some(lang) => lang.as_ref().map(|l| l.as_deref()).option(),
None => active_context.default_language(),
},
None => active_context.default_language(),
};
let direction = match active_property_definition {
Some(def) => match def.direction() {
Some(dir) => dir.option(),
None => active_context.default_base_direction(),
},
None => active_context.default_base_direction(),
};
let type_mapping: Option<JsonLdType> = match active_property_definition {
Some(def) => def.typ().cloned(),
None => None,
};
let container_mapping = match active_property_definition {
Some(def) => def.container(),
None => JsonLdContainer::Null,
};
let remove_index = (index.is_some()
&& container_mapping.contains(JsonLdContainerItem::Index))
|| index.is_none();
match value {
JsonLdValue::Literal(lit) => {
if lit.is_json() {
if type_mapping == Some(JsonLdType::Json) && remove_index {
return Ok(lit.value.clone());
} else {
let compact_key = self.with_active_context(&active_context).compact_key(
&JsonLdTerm::Keyword(JsonLdKeyword::Value),
true,
false,
location,
)?;
result.insert(compact_key.unwrap(), lit.value.clone());
let compact_key = self.with_active_context(&active_context).compact_key(
&JsonLdTerm::Keyword(JsonLdKeyword::Type),
true,
false,
location,
)?;
let compact_ty = self.with_active_context(&active_context).compact_iri(
&JsonLdTerm::Keyword(JsonLdKeyword::Json),
true,
false,
location,
)?;
result.insert(
compact_key.unwrap(),
match compact_ty {
Some(s) => JsonValue::String(s.into()),
None => JsonValue::Null,
},
);
}
} else {
let ty = match &lit.type_ {
Some(JsonLdLiteralType::Iri(iri)) => Some(iri),
_ => None,
};
if ty.cloned().map(JsonLdType::Iri) == type_mapping && remove_index {
match &lit.value {
JsonValue::Null => return Ok(JsonValue::Null),
JsonValue::Boolean(b) => return Ok(JsonValue::Boolean(*b)),
JsonValue::Number(n) => return Ok(JsonValue::Number(n.clone())),
JsonValue::String(s) => {
if ty.is_some() || (language.is_none() && direction.is_none()) {
return Ok(JsonValue::String(s.as_str().into()));
} else {
let compact_key =
self.with_active_context(&active_context).compact_key(
&JsonLdTerm::Keyword(JsonLdKeyword::Value),
true,
false,
location,
)?;
result.insert(
compact_key.unwrap(),
JsonValue::String(s.as_str().into()),
);
}
}
_ => {
let compact_key =
self.with_active_context(&active_context).compact_key(
&JsonLdTerm::Keyword(JsonLdKeyword::Value),
true,
false,
location,
)?;
result.insert(compact_key.unwrap(), lit.value.clone());
}
}
} else {
let compact_key = self.with_active_context(&active_context).compact_key(
&JsonLdTerm::Keyword(JsonLdKeyword::Value),
true,
false,
location,
)?;
result.insert(compact_key.unwrap(), lit.value.clone());
if let Some(ty) = ty {
let compact_key =
self.with_active_context(&active_context).compact_key(
&JsonLdTerm::Keyword(JsonLdKeyword::Type),
true,
false,
location,
)?;
let compact_ty =
self.with_active_context(&active_context).compact_iri(
&JsonLdTerm::Id(JsonLdLenient::iri(ty.clone())),
true,
false,
location,
)?;
result.insert(
compact_key.unwrap(),
match compact_ty {
Some(s) => JsonValue::String(s.into()),
None => JsonValue::Null,
},
);
}
}
}
}
JsonLdValue::LangString(ls) => {
let ls_language = ls.language(); let ls_direction = ls.direction();
if remove_index
&& (ls_language.is_none() || language == ls_language) && (ls_direction.is_none() || direction == ls_direction)
{
return Ok(JsonValue::String(ls.as_str().into()));
} else {
let compact_key = self.with_active_context(&active_context).compact_key(
&JsonLdTerm::Keyword(JsonLdKeyword::Value),
true,
false,
location,
)?;
result.insert(compact_key.unwrap(), JsonValue::String(ls.as_str().into()));
if let Some(language) = ls.language() {
let compact_key = self.with_active_context(&active_context).compact_key(
&JsonLdTerm::Keyword(JsonLdKeyword::Language),
true,
false,
location,
)?;
result.insert(
compact_key.unwrap(),
JsonValue::String(language.as_str().into()),
);
}
if let Some(direction) = ls.direction() {
let compact_key = self.with_active_context(&active_context).compact_key(
&JsonLdTerm::Keyword(JsonLdKeyword::Direction),
true,
false,
location,
)?;
result.insert(
compact_key.unwrap(),
JsonValue::String(direction.as_str().into()),
);
}
}
}
}
if !remove_index && let Some(index) = index {
let compact_key = self.with_active_context(&active_context).compact_key(
&JsonLdTerm::Keyword(JsonLdKeyword::Index),
true,
false,
location,
)?;
result.insert(compact_key.unwrap(), JsonValue::String(index.into()));
}
Ok(JsonValue::Object(result))
}
}
pub fn add_value(map: &mut JsonObject, key: &str, value: JsonValue, as_array: bool) {
match map
.get_unique(key)
.ok()
.unwrap()
.map(|entry| entry.is_array())
{
Some(false) => {
let (key, value) = map.remove_unique(key).ok().unwrap().unwrap();
map.insert(key, JsonValue::Array(vec![value]));
}
None if as_array => {
map.insert(key, JsonValue::Array(Vec::new()));
}
_ => (),
}
match value {
JsonValue::Array(values) => {
for value in values {
add_value(map, key, value, false)
}
}
value => {
if let Some(array) = map.get_unique_mut(key).ok().unwrap() {
array.as_array_mut().unwrap().push(value);
return;
}
map.insert(key, value);
}
}
}
pub fn value_value(value: &JsonLdValue) -> JsonValue {
match value {
JsonLdValue::Literal(lit) => lit.value.clone(),
JsonLdValue::LangString(s) => JsonValue::String(s.as_str().into()),
}
}